mirror of
https://github.com/brazilofmux/tinymux
synced 2026-08-13 00:23:11 -04:00
Phase-2 constant-notify work banned printf conversions from the catalogue
and from M_() at format call sites. Whole-sentence formats like
"You give %d %s to %s." cannot be localised that way, so Phase 3 needs a
different contract:
* tests/format/check_formats.py accepts M_("…") as a constant format and
still checks the *source* msgid against mux_vsnprintf's conversions.
* tests/nls/check_nls.py no longer bans formats in the pot; it requires
every catalogue msgstr to carry the same conversion sequence (type and
order) as its msgid. mux_vsnprintf has no positional %1$s yet.
Content: mark rob.cpp's remaining player/staff format templates with M_
(tprintf, mux_sprintf, raw_broadcast for give/kill/suspect). Constants
there were already M_ from the earlier rob notify slice. Regenerate pot,
xx, and the .mo without fuzzy entries.
Verified: make test-format, make test-nls.
443 lines
12 KiB
C++
443 lines
12 KiB
C++
/*! \file rob.cpp
|
||
* \brief Commands dealing with giving/taking/killing things or money.
|
||
*
|
||
*/
|
||
|
||
#include "copyright.h"
|
||
#include "autoconf.h"
|
||
#include "config.h"
|
||
#include "externs.h"
|
||
|
||
void do_kill
|
||
(
|
||
dbref executor,
|
||
dbref caller,
|
||
dbref enactor,
|
||
int eval,
|
||
int key,
|
||
int nargs,
|
||
UTF8 *what,
|
||
UTF8 *costchar,
|
||
const UTF8 *cargs[],
|
||
int ncargs
|
||
)
|
||
{
|
||
UNUSED_PARAMETER(caller);
|
||
UNUSED_PARAMETER(enactor);
|
||
UNUSED_PARAMETER(eval);
|
||
UNUSED_PARAMETER(nargs);
|
||
UNUSED_PARAMETER(cargs);
|
||
UNUSED_PARAMETER(ncargs);
|
||
|
||
init_match(executor, what, TYPE_PLAYER);
|
||
match_neighbor();
|
||
match_me();
|
||
match_here();
|
||
if (Long_Fingers(executor))
|
||
{
|
||
match_player();
|
||
match_absolute();
|
||
}
|
||
dbref victim = match_result();
|
||
|
||
switch (victim)
|
||
{
|
||
case NOTHING:
|
||
notify(executor, M_("I don’t see that player here."));
|
||
break;
|
||
|
||
case AMBIGUOUS:
|
||
notify(executor, M_("I don’t know who you mean!"));
|
||
break;
|
||
|
||
default:
|
||
if ( !isPlayer(victim)
|
||
&& !isThing(victim))
|
||
{
|
||
notify(executor, M_("Sorry, you can only kill players and things."));
|
||
break;
|
||
}
|
||
if ( ( Haven(Location(victim))
|
||
&& !Wizard(executor))
|
||
|| ( Controls(victim, Location(victim))
|
||
&& !Controls(executor, Location(victim)))
|
||
|| Unkillable(victim))
|
||
{
|
||
notify(executor, M_("Sorry."));
|
||
break;
|
||
}
|
||
|
||
// Go for it.
|
||
//
|
||
int cost = 0;
|
||
if (key == KILL_KILL)
|
||
{
|
||
cost = mux_atoi64(costchar);
|
||
if (cost < mudconf.killmin)
|
||
{
|
||
cost = mudconf.killmin;
|
||
}
|
||
if (cost > mudconf.killmax)
|
||
{
|
||
cost = mudconf.killmax;
|
||
}
|
||
|
||
// See if it works.
|
||
//
|
||
if (!payfor(executor, cost))
|
||
{
|
||
notify(executor, tprintf(M_("You don’t have enough %s."), mudconf.many_coins));
|
||
return;
|
||
}
|
||
}
|
||
|
||
if ( RealWizard(victim)
|
||
|| ( 0 < mudconf.killguarantee
|
||
&& !( RandomINT32(0, mudconf.killguarantee-1) < cost
|
||
|| key == KILL_SLAY)))
|
||
{
|
||
// Failure: notify player and victim only.
|
||
//
|
||
notify(executor, M_("Your murder attempt failed."));
|
||
{
|
||
LBuf buf1 = LBuf_Src("do_kill.failed");
|
||
mux_sprintf(buf1, LBUF_SIZE, M_("%s tried to kill you!"), Moniker(executor));
|
||
notify_with_cause_ooc(victim, executor, buf1, MSG_SRC_KILL);
|
||
if (Suspect(executor))
|
||
{
|
||
mux_strncpy(buf1, Moniker(executor), LBUF_SIZE-1);
|
||
if (executor == Owner(executor))
|
||
{
|
||
raw_broadcast(WIZARD, M_("[Suspect] %s tried to kill %s(#%d)."), buf1.get(), Moniker(victim), victim);
|
||
}
|
||
else
|
||
{
|
||
LBuf buf2 = LBuf_Src("do_kill.SUSP.failed");
|
||
mux_strncpy(buf2, Moniker(Owner(executor)), LBUF_SIZE-1);
|
||
raw_broadcast(WIZARD, M_("[Suspect] %s <via %s(#%d)> tried to kill %s(#%d)."),
|
||
buf2.get(), buf1.get(), executor, Moniker(victim), victim);
|
||
}
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
|
||
// Success! You killed him
|
||
//
|
||
{
|
||
LBuf buf1 = LBuf_Src("do_kill.succ.1");
|
||
LBuf buf2 = LBuf_Src("do_kill.succ.2");
|
||
if (Suspect(executor))
|
||
{
|
||
mux_strncpy(buf1, Moniker(executor), LBUF_SIZE-1);
|
||
if (executor == Owner(executor))
|
||
{
|
||
raw_broadcast(WIZARD, M_("[Suspect] %s killed %s(#%d)."), buf1.get(), Moniker(victim), victim);
|
||
}
|
||
else
|
||
{
|
||
mux_strncpy(buf2, Moniker(Owner(executor)), LBUF_SIZE-1);
|
||
raw_broadcast(WIZARD, M_("[Suspect] %s <via %s(#%d)> killed %s(#%d)."),
|
||
buf2.get(), buf1.get(), executor, Moniker(victim), victim);
|
||
}
|
||
}
|
||
mux_sprintf(buf1, LBUF_SIZE, M_("You killed %s!"), Moniker(victim));
|
||
mux_sprintf(buf2, LBUF_SIZE, M_("killed %s!"), Moniker(victim));
|
||
if (!isPlayer(victim))
|
||
{
|
||
if (halt_que(NOTHING, victim) > 0)
|
||
{
|
||
if (!Quiet(victim))
|
||
{
|
||
notify(Owner(victim), M_("Halted."));
|
||
}
|
||
}
|
||
}
|
||
did_it(executor, victim, A_KILL, buf1, A_OKILL, buf2, A_AKILL, 0,
|
||
nullptr, 0);
|
||
|
||
// notify victim
|
||
//
|
||
mux_sprintf(buf1, LBUF_SIZE, M_("%s killed you!"), Moniker(executor));
|
||
notify_with_cause_ooc(victim, executor, buf1, MSG_SRC_KILL);
|
||
|
||
// Pay off the bonus.
|
||
//
|
||
if (key == KILL_KILL)
|
||
{
|
||
cost /= 2; // Victim gets half.
|
||
if (Pennies(Owner(victim)) < mudconf.paylimit)
|
||
{
|
||
mux_sprintf(buf1, LBUF_SIZE, M_("Your insurance policy pays %d %s."), cost,
|
||
mudconf.many_coins);
|
||
notify(victim, buf1);
|
||
giveto(Owner(victim), cost);
|
||
}
|
||
else
|
||
{
|
||
notify(victim, M_("Your insurance policy has been revoked."));
|
||
}
|
||
}
|
||
}
|
||
|
||
// Send him home.
|
||
//
|
||
move_via_generic(victim, HOME, NOTHING, 0);
|
||
divest_object(victim);
|
||
break;
|
||
}
|
||
}
|
||
|
||
/*
|
||
* ---------------------------------------------------------------------------
|
||
* * give_thing, give_money, do_give: Give away money or things.
|
||
*/
|
||
|
||
static void give_thing(dbref giver, dbref recipient, int key, UTF8 *what)
|
||
{
|
||
init_match(giver, what, TYPE_THING);
|
||
match_possession();
|
||
match_me();
|
||
dbref thing = match_result();
|
||
|
||
switch (thing)
|
||
{
|
||
case NOTHING:
|
||
notify(giver, M_("You don’t have that!"));
|
||
return;
|
||
|
||
case AMBIGUOUS:
|
||
notify(giver, M_("I don’t know which you mean!"));
|
||
return;
|
||
}
|
||
if (thing == giver)
|
||
{
|
||
notify(giver, M_("You can’t give yourself away!"));
|
||
return;
|
||
}
|
||
if (thing == recipient)
|
||
{
|
||
notify(giver, M_("You can’t give an object to itself."));
|
||
return;
|
||
}
|
||
if ( (!isThing(thing) && !isPlayer(thing))
|
||
|| !( Enter_ok(recipient)
|
||
|| Controls(giver, recipient))
|
||
|| isGarbage(recipient))
|
||
{
|
||
notify(giver, NOPERM_MESSAGE);
|
||
return;
|
||
}
|
||
if (!could_doit(giver, thing, A_LGIVE))
|
||
{
|
||
LBuf str = LBuf_Src("do_give.gfail");
|
||
UTF8 *sp = str.get();
|
||
safe_str(T("You can’t give "), str, &sp);
|
||
safe_str(Moniker(thing), str, &sp);
|
||
safe_str(T(" away."), str, &sp);
|
||
*sp = '\0';
|
||
|
||
did_it(giver, thing, A_GFAIL, str, A_OGFAIL, nullptr, A_AGFAIL, 0,
|
||
nullptr, 0);
|
||
return;
|
||
}
|
||
if (!could_doit(thing, recipient, A_LRECEIVE))
|
||
{
|
||
LBuf str = LBuf_Src("do_give.rfail");
|
||
UTF8 *sp = str.get();
|
||
safe_str(Moniker(recipient), str, &sp);
|
||
safe_str(T(" doesn’t want "), str, &sp);
|
||
safe_str(Moniker(thing), str, &sp);
|
||
safe_chr('.', str, &sp);
|
||
*sp = '\0';
|
||
|
||
did_it(giver, recipient, A_RFAIL, str, A_ORFAIL, nullptr, A_ARFAIL, 0,
|
||
nullptr, 0);
|
||
return;
|
||
}
|
||
move_via_generic(thing, recipient, giver, 0);
|
||
divest_object(thing);
|
||
if (!(key & GIVE_QUIET))
|
||
{
|
||
LBuf str = LBuf_Src("do_give.thing.ok");
|
||
mux_strncpy(str, Moniker(giver), LBUF_SIZE-1);
|
||
notify_with_cause_ooc(recipient, giver, tprintf(M_("%s gave you %s."), str.get(), Moniker(thing)), MSG_SRC_GIVE);
|
||
notify(giver, M_("Given."));
|
||
notify_with_cause_ooc(thing, giver, tprintf(M_("%s gave you to %s."), str.get(), Moniker(recipient)), MSG_SRC_GIVE);
|
||
}
|
||
did_it(giver, thing, A_DROP, nullptr, A_ODROP, nullptr, A_ADROP, 0, nullptr, 0);
|
||
did_it(recipient, thing, A_SUCC, nullptr, A_OSUCC, nullptr, A_ASUCC, 0,
|
||
nullptr, 0);
|
||
}
|
||
|
||
static void give_money(dbref giver, dbref recipient, int key, int amount)
|
||
{
|
||
// Do amount consistency check.
|
||
//
|
||
if ( amount < 0
|
||
&& !Steal(giver))
|
||
{
|
||
notify(giver, tprintf(M_("You look through your pockets. Nope, no negative %s."),
|
||
mudconf.many_coins));
|
||
return;
|
||
}
|
||
if (!amount)
|
||
{
|
||
notify(giver, tprintf(M_("You must specify a positive number of %s."),
|
||
mudconf.many_coins));
|
||
return;
|
||
}
|
||
if (!Wizard(giver))
|
||
{
|
||
if ( isPlayer(recipient)
|
||
&& (Pennies(recipient) + amount > mudconf.paylimit))
|
||
{
|
||
notify(giver, tprintf(M_("That player doesn’t need that many %s!"),
|
||
mudconf.many_coins));
|
||
return;
|
||
}
|
||
if (!could_doit(giver, recipient, A_LUSE))
|
||
{
|
||
notify(giver, tprintf(M_("%s won’t take your money."), Moniker(recipient)));
|
||
return;
|
||
}
|
||
}
|
||
|
||
// Try to do the give.
|
||
//
|
||
if (!payfor(giver, amount))
|
||
{
|
||
notify(giver, tprintf(M_("You don’t have that many %s to give!"),
|
||
mudconf.many_coins));
|
||
return;
|
||
}
|
||
|
||
// Find out cost if an object.
|
||
//
|
||
int cost;
|
||
if (isThing(recipient))
|
||
{
|
||
dbref aowner;
|
||
int aflags;
|
||
LBuf str = LBuf_Adopt(atr_pget(recipient, A_COST, &aowner, &aflags));
|
||
cost = mux_atoi64(str);
|
||
|
||
// Can't afford it?
|
||
//
|
||
if (amount < cost)
|
||
{
|
||
notify(giver, M_("Feeling poor today?"));
|
||
giveto(giver, amount);
|
||
return;
|
||
}
|
||
|
||
// Negative cost
|
||
//
|
||
if (cost < 0)
|
||
{
|
||
return;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
cost = amount;
|
||
}
|
||
|
||
if (!(key & GIVE_QUIET))
|
||
{
|
||
if (amount == 1)
|
||
{
|
||
notify(giver, tprintf(M_("You give a %s to %s."), mudconf.one_coin, Moniker(recipient)));
|
||
notify_with_cause_ooc(recipient, giver, tprintf(M_("%s gives you a %s."), Moniker(giver), mudconf.one_coin), MSG_SRC_GIVE);
|
||
}
|
||
else
|
||
{
|
||
notify(giver, tprintf(M_("You give %d %s to %s."), amount, mudconf.many_coins, Moniker(recipient)));
|
||
notify_with_cause_ooc(recipient, giver, tprintf(M_("%s gives you %d %s."),
|
||
Moniker(giver), amount, mudconf.many_coins), MSG_SRC_GIVE);
|
||
}
|
||
}
|
||
|
||
// Report change given
|
||
//
|
||
if ((amount - cost) == 1)
|
||
{
|
||
notify(giver, tprintf(M_("You get 1 %s in change."), mudconf.one_coin));
|
||
giveto(giver, 1);
|
||
}
|
||
else if (amount != cost)
|
||
{
|
||
notify(giver, tprintf(M_("You get %d %s in change."), (amount - cost), mudconf.many_coins));
|
||
giveto(giver, (amount - cost));
|
||
}
|
||
|
||
// Transfer the money and run PAY attributes
|
||
//
|
||
giveto(recipient, cost);
|
||
did_it(giver, recipient, A_PAY, nullptr, A_OPAY, nullptr, A_APAY, 0, nullptr, 0);
|
||
return;
|
||
}
|
||
|
||
void do_give
|
||
(
|
||
dbref executor,
|
||
dbref caller,
|
||
dbref enactor,
|
||
int eval,
|
||
int key,
|
||
int nargs,
|
||
UTF8 *who,
|
||
UTF8 *amnt,
|
||
const UTF8 *cargs[],
|
||
int ncargs
|
||
)
|
||
{
|
||
UNUSED_PARAMETER(caller);
|
||
UNUSED_PARAMETER(enactor);
|
||
UNUSED_PARAMETER(eval);
|
||
UNUSED_PARAMETER(nargs);
|
||
UNUSED_PARAMETER(cargs);
|
||
UNUSED_PARAMETER(ncargs);
|
||
|
||
// Check recipient.
|
||
//
|
||
init_match(executor, who, TYPE_PLAYER);
|
||
match_neighbor();
|
||
match_possession();
|
||
match_me();
|
||
if (Long_Fingers(executor))
|
||
{
|
||
match_player();
|
||
match_absolute();
|
||
}
|
||
dbref recipient = match_result();
|
||
switch (recipient)
|
||
{
|
||
case NOTHING:
|
||
notify(executor, M_("Give to whom?"));
|
||
return;
|
||
|
||
case AMBIGUOUS:
|
||
notify(executor, M_("I don’t know who you mean!"));
|
||
return;
|
||
}
|
||
|
||
if (isExit(recipient))
|
||
{
|
||
notify(executor, M_("You can’t give anything to an exit."));
|
||
return;
|
||
}
|
||
if (Guest(recipient))
|
||
{
|
||
notify(executor, M_("Guests really don’t need money or anything."));
|
||
return;
|
||
}
|
||
if (is_rational(amnt))
|
||
{
|
||
give_money(executor, recipient, key, mux_atoi64(amnt));
|
||
}
|
||
else
|
||
{
|
||
give_thing(executor, recipient, key, amnt);
|
||
}
|
||
}
|