/*
* Empire - A multi-player, client/server Internet based war game.
- * Copyright (C) 1986-2000, Dave Pare, Jeff Bailey, Thomas Ruschak,
- * Ken Stevens, Steve McClure
+ * Copyright (C) 1986-2015, Dave Pare, Jeff Bailey, Thomas Ruschak,
+ * Ken Stevens, Steve McClure, Markus Armbruster
*
- * This program is free software; you can redistribute it and/or modify
+ * Empire 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 2 of the License, or
+ * 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,
* 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, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* ---
*
- * See the "LEGAL", "LICENSE", "CREDITS" and "README" files for all the
- * related information and legal notices. It is expected that any future
- * projects/authors will amend these files as needed.
+ * See files README, COPYING and CREDITS in the root of the source
+ * tree for related information and legal notices. It is expected
+ * that future projects/authors will amend these files as needed.
*
* ---
*
* look.c: Lookout from a ship or land unit
- *
+ *
* Known contributors to this file:
- *
+ * Ron Koenderink, 2006-2007
+ * Markus Armbruster, 2004-2013
*/
-#include "misc.h"
-#include "player.h"
-#include "var.h"
-#include "xy.h"
-#include "sect.h"
-#include "ship.h"
-#include "land.h"
-#include "plane.h"
-#include "nsc.h"
-#include "nat.h"
-#include "path.h"
-#include "file.h"
-#include <fcntl.h>
+#include <config.h>
+
+#include "chance.h"
#include "commands.h"
+#include "empobj.h"
+#include "map.h"
#include "optlist.h"
+#include "path.h"
-static void look_ship(register struct shpstr *lookship);
+static void look_ship(struct shpstr *lookship);
+static void look_land(struct lndstr *lookland);
int
look(void)
{
- register int i;
- struct nstr_item ni;
- struct shpstr myship;
- struct sctstr sect;
- int x, y;
- int civ;
- int mil;
- u_char *bitmap;
- int changed = 0;
+ return do_look(EF_SHIP);
+}
- if (!snxtitem(&ni, EF_SHIP, player->argp[1]))
- return RET_SYN;
- if ((bitmap = (u_char *)malloc((WORLD_X * WORLD_Y) / 8)) == 0) {
- logerror("malloc failed in look\n");
- pr("Memory error. Tell the deity.\n");
- return RET_FAIL;
- }
- bzero((s_char *)bitmap, (WORLD_X * WORLD_Y) / 8);
- while (nxtitem(&ni, (s_char *)&myship)) {
- if (!player->owner)
- continue;
- look_ship(&myship);
- for (i = 0; i <= 6; i++) {
- x = diroff[i][0] + myship.shp_x;
- y = diroff[i][1] + myship.shp_y;
- if (emp_getbit(x, y, bitmap))
- continue;
- emp_setbit(x, y, bitmap);
- getsect(x, y, §);
- if (sect.sct_type == SCT_WATER)
- continue;
- if (player->owner)
- pr("Your ");
- else
- pr("%s (#%d) ", cname(sect.sct_own),
- sect.sct_own);
- pr(dchr[sect.sct_type].d_name);
- changed += map_set(player->cnum, x, y,
- dchr[sect.sct_type].d_mnem, 0);
- pr(" %d%% efficient ", player->owner ? sect.sct_effic :
- roundintby((int)sect.sct_effic, 10));
- civ = getvar(V_CIVIL, (s_char *)§, EF_SECTOR);
- mil = getvar(V_MILIT, (s_char *)§, EF_SECTOR);
- if (civ)
- pr("with %s%d civ ", player->owner ? "" : "approx ",
- player->owner ? civ : roundintby(civ, 10));
- if (mil)
- pr("with %s%d mil ", player->owner ? "" : "approx ",
- player->owner ? mil : roundintby(mil, 10));
- pr("@ %s\n", xyas(x, y, player->cnum));
- if (opt_HIDDEN) {
- setcont(player->cnum, sect.sct_own, FOUND_LOOK);
- }
- }
- }
- if (changed)
- writemap(player->cnum);
- free((s_char *)bitmap);
- return RET_OK;
+int
+llook(void)
+{
+ return do_look(EF_LAND);
}
-static void
-look_ship(register struct shpstr *lookship)
+int
+do_look(int type)
{
- register struct shpstr *sp;
- register struct mchrstr *smcp;
- register struct mchrstr *tmcp;
- extern int ship_max_interdiction_range;
- struct sctstr sect;
- int range;
- int vrange;
- int i;
- int dist;
+ int i;
+ struct nstr_item ni;
+ union empobj_storage unit;
+ struct sctstr sect;
+ int x, y;
+ unsigned char *bitmap;
+ int changed = 0;
- range = (int) techfact(lookship->shp_tech,
- (double) mchr[(int)lookship->shp_type].m_vrnge);
- range = range * (lookship->shp_effic / 100.0);
- smcp = &mchr[(int)lookship->shp_type];
- if (smcp->m_flags & M_SUB)
- range = min(range, 1);
- for (i=0; NULL != (sp = getshipp(i)); i++) {
- if (sp->shp_own == player->cnum || sp->shp_own == 0)
- continue;
- dist = mapdist(sp->shp_x, sp->shp_y,
- lookship->shp_x, lookship->shp_y);
- if (dist > ship_max_interdiction_range)
- continue;
- tmcp = &mchr[(int)sp->shp_type];
- if (smcp->m_flags & M_SUB)
- vrange = (int)(sp->shp_visib * range/30.0);
- else
- vrange = (int)(sp->shp_visib * range/20.0);
- getsect(sp->shp_x, sp->shp_y, §);
- if (sect.sct_type != SCT_WATER)
- vrange = max(1, vrange);
- if (dist > vrange)
- continue;
- if (smcp->m_flags & M_SUB) {
- if (tmcp->m_flags & M_SONAR && dist < 2) {
- if(sp->shp_own != 0)
- wu(0, sp->shp_own,
- "%s detected surfacing noises in %s.\n",
- prship(sp),
- xyas(lookship->shp_x, lookship->shp_y,
- sp->shp_own));
- }
- if (dist == 0 && (tmcp->m_flags & M_SUB) == 0)
- if(sp->shp_own != 0)
- wu(0, sp->shp_own,
- "Periscope spotted in %s by %s\n",
- xyas(lookship->shp_x, lookship->shp_y,
- sp->shp_own),
- prship(sp));
- }
- /* subs at sea only seen by sonar */
- if (tmcp->m_flags & M_SUB && sect.sct_type == SCT_WATER)
- continue;
- pr("%s (#%d) %s @ %s\n",
- cname(sp->shp_own), sp->shp_own, prship(sp),
- xyas(sp->shp_x, sp->shp_y, player->cnum));
+ if (CANT_HAPPEN(type != EF_LAND && type != EF_SHIP))
+ type = EF_SHIP;
+
+ if (!snxtitem(&ni, type, player->argp[1], NULL))
+ return RET_SYN;
+ bitmap = calloc((WORLD_SZ() + 7) / 8, 1);
+ if (!bitmap) {
+ logerror("malloc failed in do_look\n");
+ pr("Memory error. Tell the deity.\n");
+ return RET_FAIL;
+ }
+ while (nxtitem(&ni, &unit)) {
+ if (!player->owner)
+ continue;
+ if (type == EF_LAND) {
+ if (unit.land.lnd_ship >= 0)
+ continue;
+ if (unit.land.lnd_land >= 0)
+ continue;
+ /* Spies don't need military to do a "llook". Other
+ units do */
+ if ((unit.land.lnd_item[I_MILIT] <= 0) &&
+ !(lchr[(int)unit.land.lnd_type].l_flags & L_SPY))
+ continue;
+ look_land(&unit.land);
+ } else
+ look_ship(&unit.ship);
+ for (i = 0; i <= 6; i++) {
+ x = diroff[i][0] + unit.gen.x;
+ y = diroff[i][1] + unit.gen.y;
+ if (emp_getbit(x, y, bitmap))
+ continue;
+ emp_setbit(x, y, bitmap);
+ getsect(x, y, §);
+ if (sect.sct_type == SCT_WATER)
+ continue;
+ look_at_sect(§, 10);
+ changed += map_set(player->cnum, x, y,
+ dchr[sect.sct_type].d_mnem, 0);
+ if (opt_HIDDEN) {
+ setcont(player->cnum, sect.sct_own, FOUND_LOOK);
+ }
}
+ }
+ if (changed)
+ writemap(player->cnum);
+ free(bitmap);
+ return RET_OK;
}
-static void look_land(register struct lndstr *lookland);
+void look_at_sect(struct sctstr *sp, int mult)
+{
+ int civ, mil;
+ int ours = player->god || sp->sct_own == player->cnum;
-int
-llook(void)
+ pr("%s %s",
+ sp->sct_own == player->cnum ? "Your" : prnatid(sp->sct_own),
+ dchr[sp->sct_type].d_name);
+ pr(" %d%% efficient ",
+ ours ? sp->sct_effic : roundintby(sp->sct_effic, mult));
+ civ = sp->sct_item[I_CIVIL];
+ mil = sp->sct_item[I_MILIT];
+ if (civ)
+ pr("with %s%d civ ",
+ ours ? "" : "approx ",
+ ours ? civ : roundintby(civ, mult));
+ if (mil)
+ pr("with %s%d mil ",
+ ours ? "" : "approx ",
+ ours ? mil : roundintby(mil, mult));
+ pr("@ %s\n", xyas(sp->sct_x, sp->sct_y, player->cnum));
+}
+
+static void
+look_ship(struct shpstr *lookship)
{
- register int i;
- struct nstr_item ni;
- struct lndstr myland;
- struct sctstr sect;
- int x, y;
- int civ;
- int mil;
- u_char *bitmap;
- int changed = 0;
+ struct shpstr *sp;
+ struct mchrstr *smcp;
+ struct mchrstr *tmcp;
+ struct sctstr sect;
+ int range;
+ int vrange;
+ int i;
+ int dist;
- if (!snxtitem(&ni, EF_LAND, player->argp[1]))
- return RET_SYN;
- if ((bitmap = (u_char *)malloc((WORLD_X * WORLD_Y) / 8)) == 0) {
- logerror("malloc failed in llook\n");
- pr("Memory error. Tell the deity.\n");
- return RET_FAIL;
- }
- bzero((s_char *)bitmap, (WORLD_X * WORLD_Y) / 8);
- while (nxtitem(&ni, (s_char *)&myland)) {
- if (!player->owner)
- continue;
- if (myland.lnd_ship >= 0)
- continue;
- if (myland.lnd_land >= 0)
- continue;
- /* Spies don't need military to do a "llook". Other
- units do */
- if ((lnd_getmil(&myland) <= 0) &&
- !(lchr[(int)myland.lnd_type].l_flags & L_SPY))
- continue;
- look_land(&myland);
- for (i = 0; i <= 6; i++) {
- x = diroff[i][0] + myland.lnd_x;
- y = diroff[i][1] + myland.lnd_y;
- if (emp_getbit(x, y, bitmap))
- continue;
- emp_setbit(x, y, bitmap);
- getsect(x, y, §);
- if (sect.sct_type == SCT_WATER)
- continue;
- if (player->owner)
- pr("Your ");
- else
- pr("%s (#%d) ", cname(sect.sct_own),
- sect.sct_own);
- pr(dchr[sect.sct_type].d_name);
- changed += map_set(player->cnum, x, y,
- dchr[sect.sct_type].d_mnem, 0);
- pr(" %d%% efficient ", player->owner ? sect.sct_effic :
- roundintby((int)sect.sct_effic, 10));
- civ = getvar(V_CIVIL, (s_char *)§, EF_SECTOR);
- mil = getvar(V_MILIT, (s_char *)§, EF_SECTOR);
- if (civ)
- pr("with %s%d civ ", player->owner ? "" :
- "approx ",
- player->owner ? civ : roundintby(civ, 10));
- if (mil)
- pr("with %s%d mil ", player->owner ? "" :
- "approx ",
- player->owner ? mil : roundintby(mil, 10));
- pr("@ %s\n", xyas(x, y, player->cnum));
- if (opt_HIDDEN) {
- setcont(player->cnum, sect.sct_own, FOUND_LOOK);
- }
- }
+ range = (int)techfact(lookship->shp_tech,
+ mchr[(int)lookship->shp_type].m_vrnge);
+ range = range * (lookship->shp_effic / 100.0);
+ smcp = &mchr[(int)lookship->shp_type];
+ if (smcp->m_flags & M_SUB)
+ range = MIN(range, 1);
+ for (i = 0; NULL != (sp = getshipp(i)); i++) {
+ if (sp->shp_own == player->cnum || sp->shp_own == 0)
+ continue;
+ dist = mapdist(sp->shp_x, sp->shp_y,
+ lookship->shp_x, lookship->shp_y);
+ if (dist > ship_max_interdiction_range)
+ continue;
+ tmcp = &mchr[(int)sp->shp_type];
+ if (smcp->m_flags & M_SUB)
+ vrange = (int)(shp_visib(sp) * range / 30.0);
+ else
+ vrange = (int)(shp_visib(sp) * range / 20.0);
+ getsect(sp->shp_x, sp->shp_y, §);
+ if (sect.sct_type != SCT_WATER)
+ vrange = MAX(1, vrange);
+ if (dist > vrange)
+ continue;
+ if (smcp->m_flags & M_SUB) {
+ if (tmcp->m_flags & M_SONAR && dist < 2) {
+ if (sp->shp_own != 0)
+ wu(0, sp->shp_own,
+ "%s detected surfacing noises in %s.\n",
+ prship(sp),
+ xyas(lookship->shp_x, lookship->shp_y,
+ sp->shp_own));
+ }
+ if (dist == 0 && (tmcp->m_flags & M_SUB) == 0)
+ if (sp->shp_own != 0)
+ wu(0, sp->shp_own,
+ "Periscope spotted in %s by %s\n",
+ xyas(lookship->shp_x, lookship->shp_y,
+ sp->shp_own), prship(sp));
}
- if (changed)
- writemap(player->cnum);
- free((s_char *)bitmap);
- return RET_OK;
+ /* subs at sea only seen by sonar */
+ if (tmcp->m_flags & M_SUB && sect.sct_type == SCT_WATER)
+ continue;
+ pr("%s %s @ %s\n",
+ prnatid(sp->shp_own), prship(sp),
+ xyas(sp->shp_x, sp->shp_y, player->cnum));
+ if (opt_HIDDEN)
+ setcont(player->cnum, sp->shp_own, FOUND_LOOK);
+ }
}
static void
-look_land(register struct lndstr *lookland)
+look_land(struct lndstr *lookland)
{
- register struct plnstr *pp;
- register struct lndstr *lp;
- double drange;
- int range;
- int vrange;
- int i;
- int dist;
- double techfact(int, double);
- double odds;
+ struct plnstr *pp;
+ struct lndstr *lp;
+ double drange;
+ int range;
+ int vrange;
+ int i;
+ int dist;
- drange = techfact(lookland->lnd_tech,
- (double) lookland->lnd_spy);
- drange = (drange * ((double)lookland->lnd_effic / 100.0));
- range = ldround(drange,1);
+ drange = techfact(lookland->lnd_tech, lchr[lookland->lnd_type].l_spy);
+ drange *= lookland->lnd_effic / 100.0;
+ range = ldround(drange, 1);
- if (range == 0)
- return;
+ if (range == 0)
+ return;
- for (i=0; NULL != (lp = getlandp(i)); i++) {
- if (lp->lnd_own == player->cnum || lp->lnd_own == 0)
- continue;
- if (lp->lnd_ship >= 0)
- continue;
- /* Don't always see spies */
- if (lchr[(int)lp->lnd_type].l_flags & L_SPY) {
- /* If it's on a ship or unit, assume it's hidden
- enough not to be seen */
- if (lp->lnd_ship >= 0 || lp->lnd_land >= 0)
- continue;
- odds = (double)(100 - lp->lnd_effic) + 0.10;
- if (!(chance(odds)))
- continue;
- }
- vrange = ldround((double)((lp->lnd_vis
- * range)/20.0),1);
- dist = mapdist(lp->lnd_x, lp->lnd_y,
- lookland->lnd_x, lookland->lnd_y);
- if (dist > vrange)
- continue;
-
- pr("%s (#%d) %s (approx %d mil) @ %s\n",
- cname(lp->lnd_own), lp->lnd_own,
- prland(lp), ldround((double)total_mil(lp), 20),
- xyas(lp->lnd_x, lp->lnd_y, player->cnum));
+ for (i = 0; NULL != (lp = getlandp(i)); i++) {
+ if (lp->lnd_own == player->cnum || lp->lnd_own == 0)
+ continue;
+ if (lp->lnd_ship >= 0 || lp->lnd_land >= 0)
+ continue;
+ /* Don't always see spies */
+ if (lchr[(int)lp->lnd_type].l_flags & L_SPY) {
+ /* If it's on a ship or unit, assume it's hidden
+ enough not to be seen */
+ if (lp->lnd_ship >= 0 || lp->lnd_land >= 0)
+ continue;
+ if (!(chance(LND_SPY_DETECT_CHANCE(lp->lnd_effic))))
+ continue;
}
- for (i=0; NULL != (pp = getplanep(i)); i++) {
- if (pp->pln_own == player->cnum || pp->pln_own == 0)
- continue;
- if (pp->pln_ship >= 0)
- continue;
- if (pp->pln_flags & PLN_LAUNCHED)
- continue;
- vrange = ldround((double)((10* range)/20.0),1);
- dist = mapdist(pp->pln_x, pp->pln_y,
- lookland->lnd_x, lookland->lnd_y);
- if (dist > vrange)
- continue;
+ vrange = ldround((lnd_vis(lp) * range) / 20.0, 1);
+ dist = mapdist(lp->lnd_x, lp->lnd_y,
+ lookland->lnd_x, lookland->lnd_y);
+ if (dist > vrange)
+ continue;
- pr("%s (#%d) %s @ %s\n",
- cname(pp->pln_own), pp->pln_own,
- prplane(pp),
- xyas(pp->pln_x, pp->pln_y, player->cnum));
- }
+ pr("%s %s (approx %d mil) @ %s\n",
+ prnatid(lp->lnd_own), prland(lp),
+ roundintby(lp->lnd_item[I_MILIT], 20),
+ xyas(lp->lnd_x, lp->lnd_y, player->cnum));
+ if (opt_HIDDEN)
+ setcont(player->cnum, lp->lnd_own, FOUND_LOOK);
+ }
+ for (i = 0; NULL != (pp = getplanep(i)); i++) {
+ if (pp->pln_own == player->cnum || pp->pln_own == 0)
+ continue;
+ if (pp->pln_ship >= 0 || pp->pln_land >= 0)
+ continue;
+ if (pp->pln_flags & PLN_LAUNCHED)
+ continue;
+ vrange = ldround((10 * range) / 20.0, 1);
+ dist = mapdist(pp->pln_x, pp->pln_y,
+ lookland->lnd_x, lookland->lnd_y);
+ if (dist > vrange)
+ continue;
+
+ pr("%s %s @ %s\n",
+ prnatid(pp->pln_own), prplane(pp),
+ xyas(pp->pln_x, pp->pln_y, player->cnum));
+ if (opt_HIDDEN)
+ setcont(player->cnum, pp->pln_own, FOUND_LOOK);
+ }
}