]> git.pond.sub.org Git - empserver/blob - src/lib/subs/actofgod.c
06054ee0a36fc5468f54b255245ce6bfaaeaa21b
[empserver] / src / lib / subs / actofgod.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2013, Dave Pare, Jeff Bailey, Thomas Ruschak,
4  *                Ken Stevens, Steve McClure, Markus Armbruster
5  *
6  *  Empire is free software: you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation, either version 3 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  *
19  *  ---
20  *
21  *  See files README, COPYING and CREDITS in the root of the source
22  *  tree for related information and legal notices.  It is expected
23  *  that future projects/authors will amend these files as needed.
24  *
25  *  ---
26  *
27  *  actofgod.c: Deity meddling subroutines
28  *
29  *  Known contributors to this file:
30  *     Markus Armbruster, 2013
31  */
32
33 #include <config.h>
34
35 #include <stdarg.h>
36 #include "actofgod.h"
37 #include "file.h"
38 #include "news.h"
39 #include "optlist.h"
40 #include "player.h"
41 #include "prototypes.h"
42 #include "sect.h"
43 #include "unit.h"
44
45 static void
46 nreport_divine_aid(natid whom, int goodness)
47 {
48     if (opt_GODNEWS && getnatp(whom)->nat_stat != STAT_GOD && goodness)
49         nreport(player->cnum, goodness > 0 ? N_AIDS : N_HURTS, whom, 1);
50 }
51
52 void
53 report_god_takes(char *prefix, char *what, natid from)
54 {
55     if (from && from != player->cnum) {
56         wu(0, from, "%s%s taken from you by an act of %s!\n",
57            prefix, what, cname(player->cnum));
58         nreport_divine_aid(from, -1);
59     }
60 }
61
62 void
63 report_god_gives(char *prefix, char *what, natid to)
64 {
65     if (to && to != player->cnum) {
66         wu(0, to, "%s%s given to you by an act of %s!\n",
67            prefix, what, cname(player->cnum));
68         nreport_divine_aid(to, 1);
69     }
70 }
71
72 /*
73  * Report deity meddling with sector SP.
74  * Print a message (always), send a bulletin to the sector owner and
75  * report news (sometimes).
76  * NAME names what is being changed in the sector.
77  * If CHANGE is zero, the meddling is a no-op (bulletin suppressed).
78  * If CHANGE is negative, it's secret (bulletin suppressed).
79  * If a bulletin is sent, report N_AIDS news for positive GOODNESS,
80  * N_HURTS news for negative GOODNESS
81  * The bulletin's text is like "NAME of sector X,Y changed <how> by an
82  * act of <deity>, where <deity> is the deity's name, and <how> comes
83  * from formatting printf-style FMT with optional arguments.
84  */
85 void
86 divine_sct_change(struct sctstr *sp, char *name,
87                   int change, int goodness, char *fmt, ...)
88 {
89     va_list ap;
90     char buf[4096];
91
92     va_start(ap, fmt);
93     vsnprintf(buf, sizeof(buf), fmt, ap);
94     va_end(ap);
95
96     if (!change) {
97         pr("%s of %s unchanged\n",
98            name, xyas(sp->sct_x, sp->sct_y, player->cnum));
99         return;
100     }
101
102     pr("%s of %s changed %s\n",
103        name, xyas(sp->sct_x, sp->sct_y, player->cnum), buf);
104     if (change > 0 && sp->sct_own && sp->sct_own != player->cnum) {
105         wu(0, sp->sct_own, "%s of %s changed %s by an act of %s\n",
106            name, xyas(sp->sct_x, sp->sct_y, sp->sct_own),
107            buf, cname(player->cnum));
108         nreport_divine_aid(sp->sct_own, goodness);
109     }
110 }
111
112 /*
113  * Report deity meddling with UNIT.
114  * Just like divine_sct_change(), only for ships, planes, land units,
115  * nukes.
116  */
117 void
118 divine_unit_change(struct empobj *unit, char *name,
119                    int change, int goodness, char *fmt, ...)
120 {
121     va_list ap;
122     char buf[4096];
123
124     va_start(ap, fmt);
125     vsnprintf(buf, sizeof(buf), fmt, ap);
126     va_end(ap);
127
128     if (!change) {
129         pr("%s of %s unchanged\n", name, unit_nameof(unit));
130         return;
131     }
132
133     pr("%s of %s changed %s\n", name, unit_nameof(unit), buf);
134     if (change > 0 && unit->own && unit->own != player->cnum) {
135         wu(0, unit->own, "%s of %s changed %s by an act of %s\n",
136            name, unit_nameof(unit), buf, cname(player->cnum));
137         nreport_divine_aid(unit->own, goodness);
138     }
139 }
140
141 static void
142 divine_load_unload(struct empobj *unit, int type, int uid, char *act)
143 {
144     if (uid < 0)
145         return;
146
147     pr("%s %s %s #%d\n",
148        unit_nameof(unit), act, ef_nameof(type), uid);
149     if (unit->own && unit->own != player->cnum)
150         wu(0, unit->own,
151            "%s %s %s #%d by an act of %s!\n",
152            unit_nameof(unit), act, ef_nameof(type), uid,
153            cname(player->cnum));
154     /* carrier owner could differ; can't be bothered to report to him */
155 }
156
157 void
158 divine_load(struct empobj *unit, int type, int uid)
159 {
160     union empobj_storage carrier;
161
162     divine_load_unload(unit, type, uid, "loaded onto");
163     if (get_empobj(type, uid, &carrier)
164         && (unit->x != carrier.gen.x || unit->y != carrier.gen.y)) {
165         pr("%s teleported from %s to %s!",
166            unit_nameof(unit), xyas(unit->x, unit->y, player->cnum),
167            xyas(carrier.gen.x, carrier.gen.y, player->cnum));
168         unit_teleport(unit, carrier.gen.x, carrier.gen.y);
169     }
170 }
171
172 void
173 divine_unload(struct empobj *unit, int type, int uid)
174 {
175     divine_load_unload(unit, type, uid, "unloaded from");
176 }
177
178 static int
179 fmtflags (char *buf, size_t sz, int flags, struct symbol symtab[], int all)
180 {
181     char *sep = "";
182     int n, i;
183     char *p;
184
185     if (sz)
186         buf[0] = 0;
187     n = 0;
188     for (i = 0; i < 32; i++) {
189         if (!(flags & bit(i)))
190             continue;
191         p = symbol_by_value(bit(i), symtab);
192         if (p)
193             n += snprintf(buf + n, sz - n, "%s%s", sep, p);
194         else if (all)
195             n += snprintf(buf + n, sz - n, "%s#%d", sep, i);
196         if (CANT_HAPPEN((size_t)n >= sz)) {
197             buf = NULL;
198             sz = n;
199         }
200         sep = ", ";
201     }
202     return n;
203 }
204
205 void
206 divine_flag_change(struct empobj *unit, char *name,
207                    int old, int new, struct symbol sym[])
208 {
209     char set[1024], clr[1024];
210
211     if (new == old) {
212         pr("%s of %s unchanged\n", name, unit_nameof(unit));
213         return;
214     }
215
216     fmtflags(set, sizeof(set), new & ~old, sym, 1);
217     fmtflags(clr, sizeof(clr), old & ~new, sym, 1);
218     pr("%s of %s changed: %s%s%s%s%s\n",
219        name, unit_nameof(unit),
220        set, set[0] ? " set" : "",
221        set[0] && clr[0] ? ", and " : "",
222        clr, clr[0] ? " cleared" : "");
223
224     if (fmtflags(set, sizeof(set), new & ~old, sym, 0)
225         + fmtflags(clr, sizeof(clr), old & ~new, sym, 0))
226         wu(0, unit->own, "%s of %s changed by an act of %s: %s%s%s%s%s\n",
227            name, unit_nameof(unit), cname(player->cnum),
228            set, set[0] ? " set" : "",
229            set[0] && clr[0] ? " and " : "",
230            clr, clr[0] ? " cleared" : "");
231 }
232
233 /*
234  * Report deity giving/taking commodities to/from WHOM.
235  * Give AMT of IP in PLACE.
236  */
237 void
238 report_divine_gift(natid whom, struct ichrstr *ip, int amt, char *place)
239 {
240     if (whom && whom != player->cnum && amt) {
241         if (amt > 0) {
242             if (opt_GODNEWS && getnatp(whom)->nat_stat != STAT_GOD)
243                 nreport(player->cnum, N_GIFT, whom, 1);
244             wu(0, whom, "%s gave you %d %s in %s\n",
245                cname(player->cnum), amt, ip->i_name, place);
246         } else {
247             if (opt_GODNEWS && getnatp(whom)->nat_stat != STAT_GOD)
248                 nreport(whom, N_TAKE, player->cnum, 1);
249             wu(0, whom, "%s stole %d %s from %s\n",
250                cname(player->cnum), -amt, ip->i_name, place);
251         }
252     }
253 }