diff --git a/src/figure/action.c b/src/figure/action.c index c273c7b363..8d42561387 100644 --- a/src/figure/action.c +++ b/src/figure/action.c @@ -123,6 +123,8 @@ static void (*figure_action_callbacks[])(figure *f) = { figure_soldier_action, figure_beggar_action, figure_soldier_action, + figure_enemy_catapult_action, + figure_catapult_missile_action, }; void figure_action_handle(void) diff --git a/src/figure/combat.c b/src/figure/combat.c index 2b6560eb2b..1537909d9e 100644 --- a/src/figure/combat.c +++ b/src/figure/combat.c @@ -230,6 +230,7 @@ int figure_combat_get_target_for_wolf(int x, int y, int max_distance) case FIGURE_JAVELIN: case FIGURE_BOLT: case FIGURE_BALLISTA: + case FIGURE_CATAPULT_MISSILE: case FIGURE_FRIENDLY_ARROW: case FIGURE_WATCHTOWER_ARCHER: case FIGURE_CREATURE: @@ -359,6 +360,7 @@ int figure_combat_get_missile_target_for_enemy(figure *enemy, int max_distance, case FIGURE_BOLT: case FIGURE_BALLISTA: case FIGURE_FRIENDLY_ARROW: + case FIGURE_CATAPULT_MISSILE: case FIGURE_WATCHTOWER_ARCHER: case FIGURE_CREATURE: case FIGURE_FISH_GULLS: diff --git a/src/figure/figure.c b/src/figure/figure.c index 8b61318f63..53e84640de 100644 --- a/src/figure/figure.c +++ b/src/figure/figure.c @@ -137,6 +137,7 @@ void figure_delete(figure *f) case FIGURE_JAVELIN: case FIGURE_FRIENDLY_ARROW: case FIGURE_BOLT: + case FIGURE_CATAPULT_MISSILE: case FIGURE_SPEAR: case FIGURE_FISH_GULLS: case FIGURE_SHEEP: @@ -213,7 +214,7 @@ int figure_is_dead(const figure *f) int figure_is_enemy(const figure *f) { - return f->type >= FIGURE_ENEMY43_SPEAR && f->type <= FIGURE_ENEMY_CAESAR_LEGIONARY; + return (f->type >= FIGURE_ENEMY43_SPEAR && f->type <= FIGURE_ENEMY_CAESAR_LEGIONARY) || f->type == FIGURE_ENEMY_CATAPULT; } int figure_is_legion(const figure *f) diff --git a/src/figure/name.c b/src/figure/name.c index 855e6e3af6..67d8e8494f 100644 --- a/src/figure/name.c +++ b/src/figure/name.c @@ -161,6 +161,7 @@ int figure_name_get(figure_type type, enemy_type_t enemy) case FIGURE_ENEMY51_SPEAR: case FIGURE_ENEMY52_MOUNTED_ARCHER: case FIGURE_ENEMY53_AXE: + case FIGURE_ENEMY_CATAPULT: switch (enemy) { case ENEMY_8_GREEK: return get_next_name(&data.enemy_greek, 463, 32); diff --git a/src/figure/phrase.c b/src/figure/phrase.c index bf4e8212c5..73339139c9 100644 --- a/src/figure/phrase.c +++ b/src/figure/phrase.c @@ -257,7 +257,7 @@ static const int FIGURE_TYPE_TO_SOUND_TYPE[] = { -1, -1, -1, -1, 30, -1, 31, -1, -1, -1, // 60-69 -1, -1, -1, 19, 19, 2, 1, 19, 8, 11, // 70-79 11, -1, 1, -1, -1, 19, 20, 20, 19, 19, // 80-89 - 19, -1, -1, 22, -1, -1, -1, -1, -1, -1, // 90-99 + 19, -1, -1, 22, 25, -1, -1, -1, -1, -1, // 90-99 }; enum { diff --git a/src/figure/properties.c b/src/figure/properties.c index 88b22d700e..c8e58194ff 100644 --- a/src/figure/properties.c +++ b/src/figure/properties.c @@ -476,6 +476,16 @@ static const figure_properties properties[FIGURE_TYPE_MAX] = { .max_damage = 80, .attack_value = 6, .defense_value = 0, .missile_defense_value = 0, .missile_attack_value = 4, .missile_delay = 50 }, + [FIGURE_ENEMY_CATAPULT] = { + .category = FIGURE_CATEGORY_ARMED, + .max_damage = 200, .attack_value = 1, .defense_value = 0, + .missile_defense_value = 20, .missile_attack_value = 100, .missile_delay = 200 + }, + [FIGURE_CATAPULT_MISSILE] = { + .category = FIGURE_CATEGORY_INACTIVE, + .max_damage = 100, .attack_value = 0, .defense_value = 0, + .missile_defense_value = 0, .missile_attack_value = 200, .missile_delay = 0 + }, }; diff --git a/src/figure/type.h b/src/figure/type.h index 3664a83345..92f576c477 100644 --- a/src/figure/type.h +++ b/src/figure/type.h @@ -106,7 +106,9 @@ typedef enum { FIGURE_FORT_INFANTRY = 92, FIGURE_BEGGAR = 93, FIGURE_FORT_ARCHER = 94, - FIGURE_TYPE_MAX = 95 + FIGURE_ENEMY_CATAPULT = 95, + FIGURE_CATAPULT_MISSILE = 96, + FIGURE_TYPE_MAX = 97 } figure_type; typedef enum { diff --git a/src/figuretype/enemy.c b/src/figuretype/enemy.c index bcae47b7ad..31021a0670 100644 --- a/src/figuretype/enemy.c +++ b/src/figuretype/enemy.c @@ -1,5 +1,6 @@ #include "enemy.h" +#include "assets/assets.h" #include "city/figures.h" #include "city/sound.h" #include "core/calc.h" @@ -46,7 +47,8 @@ static void enemy_initial(figure *f, formation *m) } } if (f->type == FIGURE_ENEMY43_SPEAR || f->type == FIGURE_ENEMY46_CAMEL || - f->type == FIGURE_ENEMY51_SPEAR || f->type == FIGURE_ENEMY52_MOUNTED_ARCHER) { + f->type == FIGURE_ENEMY51_SPEAR || f->type == FIGURE_ENEMY52_MOUNTED_ARCHER || + f->type == FIGURE_ENEMY_CATAPULT) { // missile throwers f->wait_ticks_missile++; map_point tile = { 0, 0 }; @@ -68,6 +70,8 @@ static void enemy_initial(figure *f, formation *m) case ENEMY_10_CARTHAGINIAN: missile_type = FIGURE_ARROW; break; + case FIGURE_ENEMY_CATAPULT: + missile_type = FIGURE_CATAPULT_MISSILE; default: missile_type = FIGURE_SPEAR; break; @@ -679,3 +683,26 @@ void figure_enemy_caesar_legionary_action(figure *f) break; } } + +void figure_enemy_catapult_action(figure *f) +{ + formation *m = formation_get(f->formation_id); + figure_image_increase_offset(f, 12); + f->cart_image_id = 0; + enemy_action(f, m); + + int dir = get_missile_direction(f, m); + + if (f->action_state == FIGURE_ACTION_149_CORPSE) { + f->image_id = assets_get_image_id("Warriors", "catapult_death_01") + figure_image_corpse_offset(f); + } else if (f->direction == DIR_FIGURE_ATTACK) { + f->image_id = assets_get_image_id("Warriors", "catapult_ne_01") + dir; + } else if (f->action_state == FIGURE_ACTION_150_ATTACK) { + f->image_id = assets_get_image_id("Warriors", "catapult_ne_01") + dir; + } else if (f->action_state == FIGURE_ACTION_151_ENEMY_INITIAL) { + f->image_id = f->image_id = assets_get_image_id("Warriors", "catapult_fe_e_01") + dir * 8 + figure_image_missile_launcher_offset(f); + } else { + f->image_id = assets_get_image_id("Warriors", "catapult_ne_01") + dir; + } + +} diff --git a/src/figuretype/enemy.h b/src/figuretype/enemy.h index efb24e76a0..38c9517f9e 100644 --- a/src/figuretype/enemy.h +++ b/src/figuretype/enemy.h @@ -29,4 +29,6 @@ void figure_enemy_gladiator_action(figure *f); void figure_enemy_caesar_legionary_action(figure *f); +void figure_enemy_catapult_action(figure *f); + #endif // FIGURETYPE_ENEMY_H diff --git a/src/figuretype/missile.c b/src/figuretype/missile.c index 52c81ed5ee..22e84815b4 100644 --- a/src/figuretype/missile.c +++ b/src/figuretype/missile.c @@ -1,5 +1,6 @@ #include "missile.h" +#include "assets/assets.h" #include "city/view.h" #include "core/image.h" #include "figure/formation.h" @@ -271,3 +272,23 @@ void figure_bolt_action(figure *f) int dir = (16 + f->direction - 2 * city_view_orientation()) % 16; f->image_id = image_group(GROUP_FIGURE_MISSILE) + 32 + dir; } + +void figure_catapult_missile_action(figure *f) +{ + f->use_cross_country = 1; + f->progress_on_tile++; + if (f->progress_on_tile > 120) { + f->state = FIGURE_STATE_DEAD; + } + int should_die = figure_movement_move_ticks_cross_country(f, 4); + int target_id = get_citizen_on_tile(f->grid_offset); + if (target_id) { + missile_hit_target(f, target_id, FIGURE_NONE); + sound_effect_play(SOUND_EFFECT_BALLISTA_HIT_GROUND); + } else if (should_die) { + f->state = FIGURE_STATE_DEAD; + } + int dir = (16 + f->direction - 2 * city_view_orientation()) % 16; + f->image_id = assets_get_image_id("Warriors", "catapult_rock_ne_01") + dir; +} + diff --git a/src/figuretype/missile.h b/src/figuretype/missile.h index 3ef5acc6ad..45d8611685 100644 --- a/src/figuretype/missile.h +++ b/src/figuretype/missile.h @@ -19,4 +19,6 @@ void figure_javelin_action(figure *f); void figure_bolt_action(figure *f); +void figure_catapult_missile_action(figure *f); + #endif // FIGURETYPE_MISSILE_H diff --git a/src/figuretype/soldier.c b/src/figuretype/soldier.c index 70f7ea49fd..17ffe89477 100644 --- a/src/figuretype/soldier.c +++ b/src/figuretype/soldier.c @@ -288,6 +288,7 @@ static void update_image_archer(figure *f, int dir) } else { f->image_id = assets_get_image_id("Warriors", "auxarch_ne_01") + dir * 12 + f->image_offset; } + } diff --git a/src/translation/english.c b/src/translation/english.c index cb7f57f3d5..92a6e9d9c4 100644 --- a/src/translation/english.c +++ b/src/translation/english.c @@ -1511,6 +1511,7 @@ static translation_string all_strings[] = { {TR_USER_DIRECTORIES_USER_PATH_CHANGED_OVERWRITE, "Overwrite existing files"}, {TR_FIGURE_TYPE_ARMORY_CARTPUSHER, "Armory deliveryman"}, {TR_TOOLTIP_BUTTON_CAN_GO_TO_ADVISORS, "Display the relevant advisor for this building." }, + {TR_FIGURE_ENEMY_CATAPULT, "Catapult"}, }; void translation_english(const translation_string **strings, int *num_strings) diff --git a/src/translation/translation.h b/src/translation/translation.h index 5c49b8809b..04e326f001 100644 --- a/src/translation/translation.h +++ b/src/translation/translation.h @@ -1503,6 +1503,7 @@ typedef enum { TR_USER_DIRECTORIES_USER_PATH_CHANGED_OVERWRITE, TR_FIGURE_TYPE_ARMORY_CARTPUSHER, TR_TOOLTIP_BUTTON_CAN_GO_TO_ADVISORS, + TR_FIGURE_ENEMY_CATAPULT, TRANSLATION_MAX_KEY } translation_key; diff --git a/src/window/building/figures.c b/src/window/building/figures.c index f86be643c3..a25afb7aa1 100644 --- a/src/window/building/figures.c +++ b/src/window/building/figures.c @@ -51,7 +51,8 @@ static const int FIGURE_TYPE_TO_BIG_FIGURE_IMAGE[] = { static const int NEW_FIGURE_TYPES[] = { TR_FIGURE_TYPE_WORK_CAMP_WORKER,TR_FIGURE_TYPE_WORK_CAMP_SLAVE,TR_FIGURE_TYPE_WORK_CAMP_ARCHITECT,TR_FIGURE_TYPE_MESS_HALL_SUPPLIER,TR_FIGURE_TYPE_MESS_HALL_COLLECTOR, TR_FIGURE_TYPE_PRIEST_SUPPLIER, TR_FIGURE_TYPE_BARKEEP, TR_FIGURE_TYPE_BARKEEP_SUPPLIER, TR_FIGURE_TYPE_TOURIST, TR_FIGURE_TYPE_WATCHMAN, 0, 0, TR_FIGURE_TYPE_CARAVANSERAI_SUPPLIER, - TR_FIGURE_TYPE_ROBBER, TR_FIGURE_TYPE_LOOTER, TR_FIGURE_TYPE_CARAVANSERAI_COLLECTOR, TR_FIGURE_TYPE_LIGHTHOUSE_SUPPLIER, TR_FIGURE_TYPE_MESS_HALL_COLLECTOR, 0, 0, TR_FIGURE_TYPE_BEGGAR + TR_FIGURE_TYPE_ROBBER, TR_FIGURE_TYPE_LOOTER, TR_FIGURE_TYPE_CARAVANSERAI_COLLECTOR, TR_FIGURE_TYPE_LIGHTHOUSE_SUPPLIER, TR_FIGURE_TYPE_MESS_HALL_COLLECTOR, 0, 0, TR_FIGURE_TYPE_BEGGAR, + 0, FIGURE_ENEMY_CATAPULT, 0 }; static generic_button figure_buttons[] = { @@ -106,6 +107,8 @@ static int big_people_image(figure_type type) return assets_get_image_id("Walkers", "overseer_portrait"); case FIGURE_MESS_HALL_SUPPLIER: return assets_get_image_id("Walkers", "quartermaster_portrait"); + case FIGURE_ENEMY_CATAPULT: + return assets_get_image_id("Warriors", "catapult_portrait"); default: break; } diff --git a/src/window/building_info.c b/src/window/building_info.c index 939155c3ef..bb4df40aa5 100644 --- a/src/window/building_info.c +++ b/src/window/building_info.c @@ -409,6 +409,7 @@ static void init(int grid_offset) case FIGURE_JAVELIN: case FIGURE_BOLT: case FIGURE_BALLISTA: + case FIGURE_CATAPULT_MISSILE: case FIGURE_CREATURE: case FIGURE_FISH_GULLS: case FIGURE_SPEAR: