1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
  
     | 
    
      /*
 * SPDX-FileCopyrightText: Copyright (C) 1987, 1988 Chuck Simmons
 * SPDX-License-Identifier: GPL-2.0+
 *
 * See the file COPYING, distributed with empire, for restriction
 * and warranty information.
 */
/*
attack.c -- handle an attack between two pieces.  We do everything from
fighting it out between the pieces to notifying the user who won and
killing off the losing object.  Somewhere far above, our caller is
responsible for actually removing the object from its list and actually
updating the player's view of the world.
Find object being attacked.  If it is a city, attacker has 50% chance
of taking city.  If successful, give city to attacker.  Otherwise
kill attacking piece.  Tell user who won.
If attacking object is not a city, loop.  On each iteration, select one
piece to throw a blow.  Damage the opponent by the strength of the blow
thrower.  Stop looping when one object has 0 or fewer hits.  Kill off
the dead object.  Tell user who won and how many hits her piece has left,
if any.
*/
#include "empire.h"
#include "extern.h"
void attack_city(piece_info_t *att_obj, loc_t loc) {
	city_info_t *cityp;
	int att_owner, city_owner;
	cityp = find_city(loc);
	ASSERT(cityp != NULL);
	att_owner = att_obj->owner;
	// cppcheck-suppress nullPointerRedundantCheck
	city_owner = cityp->owner;
	if (irand(2) == 0) { /* attack fails? */
		if (att_owner == USER) {
			comment("The scum defending the city crushed your "
			        "attacking blitzkrieger.");
			ksend("The scum defending the city crushed your "
			      "attacking blitzkrieger.\n"); // kermyt
		} else if (city_owner == USER) {
			ksend("Your city at %d is under attack.\n",
			      loc_disp(cityp->loc)); // kermyt
			comment("Your city at %d is under attack.",
			        loc_disp(cityp->loc));
		}
		kill_obj(att_obj, loc);
	} else { /* attack succeeded */
		kill_city(cityp);
		cityp->owner = att_owner;
		kill_obj(att_obj, loc);
		if (att_owner == USER) {
			ksend("City at %d has been subjugated!\n",
			      loc_disp(cityp->loc)); // kermyt
			error("City at %d has been subjugated!",
			      loc_disp(cityp->loc));
			extra(
			    "Your army has been dispersed to enforce control.");
			ksend("Your army has been dispersed to enforce "
			      "control.\n");
			set_prod(cityp);
		} else if (city_owner == USER) {
			ksend("City at %d has been lost to the enemy!\n",
			      loc_disp(cityp->loc)); // kermyt
			comment("City at %d has been lost to the enemy!",
			        loc_disp(cityp->loc));
		}
	}
	/* let city owner see all results */
	if (city_owner != UNOWNED) {
		scan(MAP(city_owner), loc);
	}
}
/*
Attack a piece other than a city.  The piece could be anyone's.
First we have to figure out what is being attacked.
*/
void attack_obj(piece_info_t *att_obj, loc_t loc) {
	void describe(piece_info_t *, piece_info_t *, loc_t);
	void survive(piece_info_t *, loc_t);
	piece_info_t *def_obj; /* defender */
	int owner;
	def_obj = find_obj_at_loc(loc);
	ASSERT(def_obj != NULL); /* can't find object to attack? */
	// cppcheck-suppress nullPointerRedundantCheck
	if (def_obj->type == SATELLITE) {
		return; /* can't attack a satellite */
	}
	while (att_obj->hits > 0 && def_obj->hits > 0) {
		if (irand(2) == 0) /* defender hits? */ {
			att_obj->hits -= piece_attr[def_obj->type].strength;
		} else {
			def_obj->hits -= piece_attr[att_obj->type].strength;
		}
	}
	if (att_obj->hits > 0) { /* attacker won? */
		describe(att_obj, def_obj, loc);
		owner = def_obj->owner;
		kill_obj(def_obj, loc); /* kill loser */
		survive(att_obj, loc);  /* move attacker */
	} else {                        /* defender won */
		describe(def_obj, att_obj, loc);
		owner = att_obj->owner;
		kill_obj(att_obj, loc);
		survive(def_obj, loc);
	}
	/* show results to first killed */
	scan(MAP(owner), loc);
}
void attack(piece_info_t *att_obj, loc_t loc) {
	if (game.real_map[loc].contents == MAP_CITY) /* attacking a city? */ {
		attack_city(att_obj, loc);
	} else {
		attack_obj(att_obj, loc); /* attacking a piece */
	}
}
/*
Here we look to see if any cargo was killed in the attack.  If
a ships contents exceeds its capacity, some of the survivors
fall overboard and drown.  We also move the survivor to the given
location.
*/
void survive(piece_info_t *obj, loc_t loc) {
	while (obj_capacity(obj) < obj->count) {
		kill_obj(obj->cargo, loc);
	}
	move_obj(obj, loc);
}
void describe(piece_info_t *win_obj, piece_info_t *lose_obj, loc_t loc) {
	char buf[STRSIZE];
	char buf2[STRSIZE];
	*buf = '\0';
	*buf2 = '\0';
	if (win_obj->owner != lose_obj->owner) {
		if (win_obj->owner == USER) {
			int diff;
			game.user_score +=
			    piece_attr[lose_obj->type].build_time;
			ksend("Enemy %s at %d destroyed.\n",
			      piece_attr[lose_obj->type].name,
			      loc_disp(loc)); // kermyt
			topmsg(1, "Enemy %s at %d destroyed.",
			       piece_attr[lose_obj->type].name, loc_disp(loc));
			ksend("Your %s has %d hits left\n",
			      piece_attr[win_obj->type].name,
			      win_obj->hits); // kermyt
			topmsg(2, "Your %s has %d hits left.",
			       piece_attr[win_obj->type].name, win_obj->hits);
			diff = win_obj->count - obj_capacity(win_obj);
			if (diff > 0) {
				switch (win_obj->cargo->type) {
				case ARMY:
					ksend("%d armies fell overboard and "
					      "drowned in the assault.\n",
					      diff); // kermyt
					topmsg(3,
					       "%d armies fell overboard and "
					       "drowned in the assault.",
					       diff);
					break;
				case FIGHTER:
					ksend("%d fighters fell overboard and "
					      "were lost in the assult.\n",
					      diff); // kermyt
					topmsg(3,
					       "%d fighters fell overboard and "
					       "were lost in the assault.",
					       diff);
					break;
				}
			}
		} else {
			game.comp_score +=
			    piece_attr[lose_obj->type].build_time;
			ksend("Your %s at %d destroyed.\n",
			      piece_attr[lose_obj->type].name,
			      loc_disp(loc)); // kermyt
			topmsg(3, "Your %s at %d destroyed.",
			       piece_attr[lose_obj->type].name, loc_disp(loc));
		}
		set_need_delay();
	}
}
/* end */
 
     |