- scriptified ArtiHealingRadius.

- allow switch/case with names.
- fixed break jump target handling for switch/case. This only worked when the break was in the outermost compound statement, those in inner ones were missed.
This commit is contained in:
Christoph Oelckers 2016-11-27 00:18:07 +01:00
commit 69d4d36429
9 changed files with 151 additions and 120 deletions

View file

@ -1,95 +0,0 @@
/*
#include "info.h"
#include "a_pickups.h"
#include "a_artifacts.h"
#include "gstrings.h"
#include "p_local.h"
#include "s_sound.h"
#include "m_random.h"
#include "a_action.h"
#include "a_hexenglobal.h"
#include "gi.h"
#include "doomstat.h"
*/
#define HEAL_RADIUS_DIST 255.
static FRandom pr_healradius ("HealRadius");
// Healing Radius Artifact --------------------------------------------------
class AArtiHealingRadius : public AInventory
{
DECLARE_CLASS (AArtiHealingRadius, AInventory)
public:
bool Use (bool pickup);
};
IMPLEMENT_CLASS(AArtiHealingRadius, false, false)
bool AArtiHealingRadius::Use (bool pickup)
{
bool effective = false;
FName mode;
if (Owner->IsKindOf(RUNTIME_CLASS(APlayerPawn)))
{
mode = static_cast<PClassPlayerPawn *>(Owner->GetClass())->HealingRadiusType;
}
for (int i = 0; i < MAXPLAYERS; ++i)
{
if (playeringame[i] &&
players[i].mo != NULL &&
players[i].mo->health > 0 &&
players[i].mo->Distance2D (Owner) <= HEAL_RADIUS_DIST)
{
// Q: Is it worth it to make this selectable as a player property?
// A: Probably not - but it sure doesn't hurt.
bool gotsome=false;
switch (mode)
{
case NAME_Armor:
for (int j = 0; j < 4; ++j)
{
AHexenArmor *armor = Spawn<AHexenArmor> ();
armor->health = j;
armor->Amount = 1;
if (!armor->CallTryPickup (players[i].mo))
{
armor->Destroy ();
}
else
{
gotsome = true;
}
}
break;
case NAME_Mana:
{
int amount = 50 + (pr_healradius() % 50);
if (players[i].mo->GiveAmmo (dyn_cast<PClassAmmo>(PClass::FindClass(NAME_Mana1)), amount) ||
players[i].mo->GiveAmmo (dyn_cast<PClassAmmo>(PClass::FindClass(NAME_Mana2)), amount))
{
gotsome = true;
}
break;
}
default:
//case NAME_Health:
gotsome = P_GiveBody (players[i].mo, 50 + (pr_healradius()%50));
break;
}
if (gotsome)
{
S_Sound (players[i].mo, CHAN_AUTO, "MysticIncant", 1, ATTN_NORM);
effective=true;
}
}
}
return effective;
}

View file

@ -26,7 +26,6 @@
// Include all the Hexen stuff here to reduce compile time
#include "a_flechette.cpp"
#include "a_flies.cpp"
#include "a_healingradius.cpp"
#include "a_heresiarch.cpp"
#include "a_hexenspecialdecs.cpp"
#include "a_iceguy.cpp"

View file

@ -1093,7 +1093,6 @@ DEFINE_ACTION_FUNCTION(AActor, GiveInventoryType)
ACTION_RETURN_OBJECT(self->GiveInventoryType(type));
}
//============================================================================
//
// AActor :: GiveAmmo
@ -1122,6 +1121,14 @@ bool AActor::GiveAmmo (PClassAmmo *type, int amount)
return false;
}
DEFINE_ACTION_FUNCTION(AActor, GiveAmmo)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_CLASS(type, AAmmo);
PARAM_INT(amount);
ACTION_RETURN_BOOL(self->GiveAmmo(type, amount));
}
//============================================================================
//
// AActor :: ClearInventory

View file

@ -3175,6 +3175,19 @@ DEFINE_FIELD(APlayerPawn, FlechetteType)
DEFINE_FIELD(APlayerPawn, DamageFade)
DEFINE_FIELD(APlayerPawn, ViewBob)
DEFINE_FIELD(PClassPlayerPawn, HealingRadiusType)
DEFINE_FIELD(PClassPlayerPawn, DisplayName)
DEFINE_FIELD(PClassPlayerPawn, SoundClass)
DEFINE_FIELD(PClassPlayerPawn, Face)
DEFINE_FIELD(PClassPlayerPawn, Portrait)
DEFINE_FIELD(PClassPlayerPawn, Slot)
DEFINE_FIELD(PClassPlayerPawn, InvulMode)
DEFINE_FIELD(PClassPlayerPawn, HexenArmor)
DEFINE_FIELD(PClassPlayerPawn, ColorRangeStart)
DEFINE_FIELD(PClassPlayerPawn, ColorRangeEnd)
DEFINE_FIELD(PClassPlayerPawn, ColorSets)
DEFINE_FIELD(PClassPlayerPawn, PainFlashes)
DEFINE_FIELD_X(PlayerInfo, player_t, mo)
DEFINE_FIELD_X(PlayerInfo, player_t, playerstate)
DEFINE_FIELD_X(PlayerInfo, player_t, original_oldbuttons)

View file

@ -8338,7 +8338,7 @@ bool FxCompoundStatement::CheckLocalVariable(FName name)
FxSwitchStatement::FxSwitchStatement(FxExpression *cond, FArgumentList &content, const FScriptPosition &pos)
: FxExpression(EFX_SwitchStatement, pos)
{
Condition = new FxIntCast(cond, false);
Condition = cond;
Content = std::move(content);
}
@ -8352,6 +8352,12 @@ FxExpression *FxSwitchStatement::Resolve(FCompileContext &ctx)
CHECKRESOLVED();
SAFE_RESOLVE(Condition, ctx);
if (Condition->ValueType != TypeName)
{
Condition = new FxIntCast(Condition, false);
SAFE_RESOLVE(Condition, ctx);
}
if (Content.Size() == 0)
{
ScriptPosition.Message(MSG_WARNING, "Empty switch statement");
@ -8370,15 +8376,15 @@ FxExpression *FxSwitchStatement::Resolve(FCompileContext &ctx)
}
}
auto outerctrl = ctx.ControlStmt;
ctx.ControlStmt = this;
for (auto &line : Content)
{
// Do not resolve breaks, they need special treatment inside switch blocks.
if (line->ExprType != EFX_JumpStatement || static_cast<FxJumpStatement *>(line)->Token != TK_Break)
{
SAFE_RESOLVE(line, ctx);
line->NeedResult = false;
}
SAFE_RESOLVE(line, ctx);
line->NeedResult = false;
}
ctx.ControlStmt = outerctrl;
if (Condition->isConstant())
{
@ -8398,6 +8404,12 @@ FxExpression *FxSwitchStatement::Resolve(FCompileContext &ctx)
auto casestmt = static_cast<FxCaseStatement *>(content[i]);
if (casestmt->Condition == nullptr) defaultindex = i;
else if (casestmt->CaseValue == static_cast<FxConstant *>(Condition)->GetValue().GetInt()) caseindex = i;
if (casestmt->Condition && casestmt->Condition->ValueType != Condition->ValueType)
{
casestmt->Condition->ScriptPosition.Message(MSG_ERROR, "Type mismatch in case statement");
delete this;
return nullptr;
}
}
if (content[i]->ExprType == EFX_JumpStatement && static_cast<FxJumpStatement *>(content[i])->Token == TK_Break)
{
@ -8478,7 +8490,6 @@ ExpEmit FxSwitchStatement::Emit(VMFunctionBuilder *build)
ca.jumpaddress = build->Emit(OP_JMP, 0);
}
size_t DefaultAddress = build->Emit(OP_JMP, 0);
TArray<size_t> BreakAddresses;
bool defaultset = false;
for (auto line : Content)
@ -8504,22 +8515,14 @@ ExpEmit FxSwitchStatement::Emit(VMFunctionBuilder *build)
}
break;
case EFX_JumpStatement:
if (static_cast<FxJumpStatement *>(line)->Token == TK_Break)
{
BreakAddresses.Push(build->Emit(OP_JMP, 0));
break;
}
// fall through for continue.
default:
line->Emit(build);
break;
}
}
for (auto addr : BreakAddresses)
for (auto addr : Breaks)
{
build->BackpatchToHere(addr);
build->BackpatchToHere(addr->Address);
}
if (!defaultset) build->BackpatchToHere(DefaultAddress);
Content.DeleteAndClear();
@ -8555,7 +8558,7 @@ bool FxSwitchStatement::CheckReturn()
FxCaseStatement::FxCaseStatement(FxExpression *cond, const FScriptPosition &pos)
: FxExpression(EFX_CaseStatement, pos)
{
Condition = cond? new FxIntCast(cond, false) : nullptr;
Condition = cond;
}
FxCaseStatement::~FxCaseStatement()
@ -8576,7 +8579,17 @@ FxExpression *FxCaseStatement::Resolve(FCompileContext &ctx)
delete this;
return nullptr;
}
CaseValue = static_cast<FxConstant *>(Condition)->GetValue().GetInt();
// Case labels can be ints or names.
if (Condition->ValueType != TypeName)
{
Condition = new FxIntCast(Condition, false);
SAFE_RESOLVE(Condition, ctx);
CaseValue = static_cast<FxConstant *>(Condition)->GetValue().GetInt();
}
else
{
CaseValue = static_cast<FxConstant *>(Condition)->GetValue().GetName();
}
}
return this;
}
@ -8747,10 +8760,13 @@ bool FxIfStatement::CheckReturn()
FxExpression *FxLoopStatement::Resolve(FCompileContext &ctx)
{
auto outerctrl = ctx.ControlStmt;
auto outer = ctx.Loop;
ctx.ControlStmt = this;
ctx.Loop = this;
auto x = DoResolve(ctx);
ctx.Loop = outer;
ctx.ControlStmt = outerctrl;
return x;
}
@ -9074,9 +9090,17 @@ FxExpression *FxJumpStatement::Resolve(FCompileContext &ctx)
{
CHECKRESOLVED();
if (ctx.Loop != nullptr)
if (ctx.ControlStmt != nullptr)
{
ctx.Loop->Jumps.Push(this);
if (ctx.ControlStmt == ctx.Loop || Token == TK_Continue)
{
ctx.Loop->Jumps.Push(this);
}
else
{
// break in switch.
static_cast<FxSwitchStatement*>(ctx.ControlStmt)->Breaks.Push(this);
}
return this;
}
else

View file

@ -72,6 +72,7 @@ typedef TDeletingArray<FxExpression*> FArgumentList;
struct FCompileContext
{
FxExpression *ControlStmt = nullptr;
FxLoopStatement *Loop = nullptr;
FxCompoundStatement *Block = nullptr;
PPrototype *ReturnProto;
@ -1656,6 +1657,8 @@ class FxSwitchStatement : public FxExpression
TArray<CaseAddr> CaseAddresses;
public:
TArray<FxJumpStatement *> Breaks;
FxSwitchStatement(FxExpression *cond, FArgumentList &content, const FScriptPosition &pos);
~FxSwitchStatement();
FxExpression *Resolve(FCompileContext&);