]> git.pond.sub.org Git - empserver/blob - src/lib/subs/actofgod.c
63a70f635ae48312a407c88ed10a6db1a6f45860
[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 NP.
114  * Just like divine_sct_change(), only for nations.
115  */
116 void
117 divine_nat_change(struct natstr *np, char *name,
118                    int change, int goodness, char *fmt, ...)
119 {
120     va_list ap;
121     char buf[4096];
122
123     va_start(ap, fmt);
124     vsnprintf(buf, sizeof(buf), fmt, ap);
125     va_end(ap);
126
127     if (!change) {
128         pr("%s of %s unchanged\n", name, prnat(np));
129         return;
130     }
131
132     pr("%s of %s changed %s\n", name, prnat(np), buf);
133     if (change > 0 && np->nat_cnum != player->cnum) {
134         wu(0, np->nat_cnum, "%s changed %s by an act of %s!\n",
135            name, buf, cname(player->cnum));
136         nreport_divine_aid(np->nat_cnum, goodness);
137     }
138 }
139
140 /*
141  * Report deity meddling with UNIT.
142  * Just like divine_sct_change(), only for ships, planes, land units,
143  * nukes.
144  */
145 void
146 divine_unit_change(struct empobj *unit, char *name,
147                    int change, int goodness, char *fmt, ...)
148 {
149     va_list ap;
150     char buf[4096];
151
152     va_start(ap, fmt);
153     vsnprintf(buf, sizeof(buf), fmt, ap);
154     va_end(ap);
155
156     if (!change) {
157         pr("%s of %s unchanged\n", name, unit_nameof(unit));
158         return;
159     }
160
161     pr("%s of %s changed %s\n", name, unit_nameof(unit), buf);
162     if (change > 0 && unit->own && unit->own != player->cnum) {
163         wu(0, unit->own, "%s of %s changed %s by an act of %s\n",
164            name, unit_nameof(unit), buf, cname(player->cnum));
165         nreport_divine_aid(unit->own, goodness);
166     }
167 }
168
169 static void
170 divine_load_unload(struct empobj *unit, int type, int uid, char *act)
171 {
172     if (uid < 0)
173         return;
174
175     pr("%s %s %s #%d\n",
176        unit_nameof(unit), act, ef_nameof(type), uid);
177     if (unit->own && unit->own != player->cnum)
178         wu(0, unit->own,
179            "%s %s %s #%d by an act of %s!\n",
180            unit_nameof(unit), act, ef_nameof(type), uid,
181            cname(player->cnum));
182     /* carrier owner could differ; can't be bothered to report to him */
183 }
184
185 void
186 divine_load(struct empobj *unit, int type, int uid)
187 {
188     union empobj_storage carrier;
189
190     divine_load_unload(unit, type, uid, "loaded onto");
191     if (get_empobj(type, uid, &carrier)
192         && (unit->x != carrier.gen.x || unit->y != carrier.gen.y)) {
193         pr("%s teleported from %s to %s!",
194            unit_nameof(unit), xyas(unit->x, unit->y, player->cnum),
195            xyas(carrier.gen.x, carrier.gen.y, player->cnum));
196         unit_teleport(unit, carrier.gen.x, carrier.gen.y);
197     }
198 }
199
200 void
201 divine_unload(struct empobj *unit, int type, int uid)
202 {
203     divine_load_unload(unit, type, uid, "unloaded from");
204 }
205
206 static int
207 fmtflags (char *buf, size_t sz, int flags, struct symbol symtab[], int all)
208 {
209     char *sep = "";
210     int n, i;
211     char *p;
212
213     if (buf && sz)
214         buf[0] = 0;
215     n = 0;
216     for (i = 0; i < 32; i++) {
217         if (!(flags & bit(i)))
218             continue;
219         p = symbol_by_value(bit(i), symtab);
220         if (p)
221             n += snprintf(buf + n, sz - n, "%s%s", sep, p);
222         else if (all)
223             n += snprintf(buf + n, sz - n, "%s#%d", sep, i);
224         if ((size_t)n >= sz)
225             sz = n;
226         sep = ", ";
227     }
228
229     CANT_HAPPEN((size_t)n >= sz && buf);
230     return n;
231 }
232
233 void
234 divine_flag_change(struct empobj *unit, char *name,
235                    int old, int new, struct symbol sym[])
236 {
237     char set[1024], clr[1024];
238
239     if (new == old) {
240         pr("%s of %s unchanged\n", name, unit_nameof(unit));
241         return;
242     }
243
244     fmtflags(set, sizeof(set), new & ~old, sym, 1);
245     fmtflags(clr, sizeof(clr), old & ~new, sym, 1);
246     pr("%s of %s changed: %s%s%s%s%s\n",
247        name, unit_nameof(unit),
248        set, set[0] ? " set" : "",
249        set[0] && clr[0] ? ", and " : "",
250        clr, clr[0] ? " cleared" : "");
251
252     if (fmtflags(set, sizeof(set), new & ~old, sym, 0)
253         + fmtflags(clr, sizeof(clr), old & ~new, sym, 0))
254         wu(0, unit->own, "%s of %s changed by an act of %s: %s%s%s%s%s\n",
255            name, unit_nameof(unit), cname(player->cnum),
256            set, set[0] ? " set" : "",
257            set[0] && clr[0] ? " and " : "",
258            clr, clr[0] ? " cleared" : "");
259 }
260
261 /*
262  * Report deity giving/taking commodities to/from WHOM.
263  * Give AMT of IP in PLACE.
264  */
265 void
266 report_divine_gift(natid whom, struct ichrstr *ip, int amt, char *place)
267 {
268     if (whom && whom != player->cnum && amt) {
269         if (amt > 0) {
270             if (opt_GODNEWS && getnatp(whom)->nat_stat != STAT_GOD)
271                 nreport(player->cnum, N_GIFT, whom, 1);
272             wu(0, whom, "%s gave you %d %s in %s\n",
273                cname(player->cnum), amt, ip->i_name, place);
274         } else {
275             if (opt_GODNEWS && getnatp(whom)->nat_stat != STAT_GOD)
276                 nreport(whom, N_TAKE, player->cnum, 1);
277             wu(0, whom, "%s stole %d %s from %s\n",
278                cname(player->cnum), -amt, ip->i_name, place);
279         }
280     }
281 }