- scriptified Chicken and Pig - not tested yet, because other things have priority.

This commit is contained in:
Christoph Oelckers 2016-11-22 12:21:55 +01:00
commit bbb0778fd4
16 changed files with 309 additions and 357 deletions

View file

@ -867,7 +867,6 @@ set( NOT_COMPILED_SOURCE_FILES
sc_man_scanner.h
sc_man_scanner.re
g_doom/a_painelemental.cpp
g_heretic/a_chicken.cpp
g_heretic/a_dsparil.cpp
g_heretic/a_hereticartifacts.cpp
g_heretic/a_hereticweaps.cpp
@ -892,7 +891,6 @@ set( NOT_COMPILED_SOURCE_FILES
g_hexen/a_magecone.cpp
g_hexen/a_magelightning.cpp
g_hexen/a_magestaff.cpp
g_hexen/a_pig.cpp
g_hexen/a_serpent.cpp
g_hexen/a_spike.cpp
g_hexen/a_summon.cpp

View file

@ -100,6 +100,7 @@ FString GetPrintableDisplayName(PClassPlayerPawn *cls);
class APlayerPawn : public AActor
{
DECLARE_CLASS_WITH_META(APlayerPawn, AActor, PClassPlayerPawn)
HAS_FIELDS
HAS_OBJECT_POINTERS
public:
@ -116,7 +117,7 @@ public:
virtual void PlayRunning ();
virtual void ThrowPoisonBag ();
virtual void TweakSpeeds (double &forwardmove, double &sidemove);
virtual void MorphPlayerThink ();
void MorphPlayerThink ();
virtual void ActivateMorphWeapon ();
AWeapon *PickNewWeapon (PClassAmmo *ammotype);
AWeapon *BestWeapon (PClassAmmo *ammotype);

View file

@ -1,233 +0,0 @@
/*
#include "actor.h"
#include "gi.h"
#include "m_random.h"
#include "s_sound.h"
#include "d_player.h"
#include "a_action.h"
#include "a_pickups.h"
#include "p_local.h"
#include "a_sharedglobal.h"
#include "p_enemy.h"
#include "d_event.h"
#include "gstrings.h"
#include "vm.h"
*/
void P_UpdateBeak (AActor *actor);
static FRandom pr_chickenplayerthink ("ChickenPlayerThink");
static FRandom pr_chicattack ("ChicAttack");
static FRandom pr_feathers ("Feathers");
static FRandom pr_beakatkpl1 ("BeakAtkPL1");
static FRandom pr_beakatkpl2 ("BeakAtkPL2");
class AChickenPlayer : public APlayerPawn
{
DECLARE_CLASS (AChickenPlayer, APlayerPawn)
public:
void MorphPlayerThink ();
};
IMPLEMENT_CLASS(AChickenPlayer, false, false, false, false)
void AChickenPlayer::MorphPlayerThink ()
{
if (health > 0)
{ // Handle beak movement
P_UpdateBeak (this);
}
if (player->morphTics & 15)
{
return;
}
if (Vel.X == 0 && Vel.Y == 0 && pr_chickenplayerthink () < 160)
{ // Twitch view angle
Angles.Yaw += pr_chickenplayerthink.Random2() * (360. / 256. / 32.);
}
if ((Z() <= floorz) && (pr_chickenplayerthink() < 32))
{ // Jump and noise
Vel.Z += JumpZ;
FState * painstate = FindState(NAME_Pain);
if (painstate != NULL) SetState (painstate);
}
if (pr_chickenplayerthink () < 48)
{ // Just noise
S_Sound (this, CHAN_VOICE, "chicken/active", 1, ATTN_NORM);
}
}
//----------------------------------------------------------------------------
//
// PROC A_ChicAttack
//
//----------------------------------------------------------------------------
DEFINE_ACTION_FUNCTION(AActor, A_ChicAttack)
{
PARAM_SELF_PROLOGUE(AActor);
if (!self->target)
{
return 0;
}
if (self->CheckMeleeRange())
{
int damage = 1 + (pr_chicattack() & 1);
int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee);
P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self);
}
return 0;
}
//----------------------------------------------------------------------------
//
// PROC A_Feathers
//
//----------------------------------------------------------------------------
DEFINE_ACTION_FUNCTION(AActor, A_Feathers)
{
PARAM_SELF_PROLOGUE(AActor);
int i;
int count;
AActor *mo;
if (self->health > 0)
{ // Pain
count = pr_feathers() < 32 ? 2 : 1;
}
else
{ // Death
count = 5 + (pr_feathers()&3);
}
for (i = 0; i < count; i++)
{
mo = Spawn("Feather", self->PosPlusZ(20.), NO_REPLACE);
mo->target = self;
mo->Vel.X = pr_feathers.Random2() / 256.;
mo->Vel.Y = pr_feathers.Random2() / 256.;
mo->Vel.Z = 1. + pr_feathers() / 128.;
mo->SetState (mo->SpawnState + (pr_feathers()&7));
}
return 0;
}
//---------------------------------------------------------------------------
//
// PROC P_UpdateBeak
//
//---------------------------------------------------------------------------
void P_UpdateBeak (AActor *self)
{
DPSprite *pspr;
if (self->player != nullptr && (pspr = self->player->FindPSprite(PSP_WEAPON)) != nullptr)
{
pspr->y = WEAPONTOP + self->player->chickenPeck / 2;
}
}
//---------------------------------------------------------------------------
//
// PROC A_BeakRaise
//
//---------------------------------------------------------------------------
DEFINE_ACTION_FUNCTION(AActor, A_BeakRaise)
{
PARAM_ACTION_PROLOGUE(AActor);
player_t *player;
if (nullptr == (player = self->player))
{
return 0;
}
player->GetPSprite(PSP_WEAPON)->y = WEAPONTOP;
P_SetPsprite(player, PSP_WEAPON, player->ReadyWeapon->GetReadyState());
return 0;
}
//----------------------------------------------------------------------------
//
// PROC P_PlayPeck
//
//----------------------------------------------------------------------------
void P_PlayPeck (AActor *chicken)
{
S_Sound (chicken, CHAN_VOICE, "chicken/peck", 1, ATTN_NORM);
}
//----------------------------------------------------------------------------
//
// PROC A_BeakAttackPL1
//
//----------------------------------------------------------------------------
DEFINE_ACTION_FUNCTION(AActor, A_BeakAttackPL1)
{
PARAM_ACTION_PROLOGUE(AActor);
DAngle angle;
int damage;
DAngle slope;
player_t *player;
FTranslatedLineTarget t;
if (NULL == (player = self->player))
{
return 0;
}
damage = 1 + (pr_beakatkpl1()&3);
angle = player->mo->Angles.Yaw;
slope = P_AimLineAttack (player->mo, angle, MELEERANGE);
P_LineAttack (player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, "BeakPuff", true, &t);
if (t.linetarget)
{
player->mo->Angles.Yaw = t.angleFromSource;
}
P_PlayPeck (player->mo);
player->chickenPeck = 12;
player->GetPSprite(PSP_WEAPON)->Tics -= pr_beakatkpl1() & 7;
return 0;
}
//----------------------------------------------------------------------------
//
// PROC A_BeakAttackPL2
//
//----------------------------------------------------------------------------
DEFINE_ACTION_FUNCTION(AActor, A_BeakAttackPL2)
{
PARAM_ACTION_PROLOGUE(AActor);
DAngle angle;
int damage;
DAngle slope;
player_t *player;
FTranslatedLineTarget t;
if (NULL == (player = self->player))
{
return 0;
}
damage = pr_beakatkpl2.HitDice (4);
angle = player->mo->Angles.Yaw;
slope = P_AimLineAttack (player->mo, angle, MELEERANGE);
P_LineAttack (player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, "BeakPuff", true, &t);
if (t.linetarget)
{
player->mo->Angles.Yaw = t.angleFromSource;
}
P_PlayPeck (player->mo);
player->chickenPeck = 12;
player->GetPSprite(PSP_WEAPON)->Tics -= pr_beakatkpl2()&3;
return 0;
}

View file

@ -19,7 +19,6 @@
#include "serializer.h"
// Include all the other Heretic stuff here to reduce compile time
#include "a_chicken.cpp"
#include "a_dsparil.cpp"
#include "a_hereticartifacts.cpp"
#include "a_hereticweaps.cpp"

View file

@ -49,6 +49,13 @@ void AdjustPlayerAngle (AActor *pmo, FTranslatedLineTarget *t)
}
}
DEFINE_ACTION_FUNCTION(AActor, AdjustPlayerAngle)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_POINTER(t, FTranslatedLineTarget);
AdjustPlayerAngle(self, t);
return 0;
}
//============================================================================
//
// TryPunch

View file

@ -45,7 +45,6 @@
#include "a_magecone.cpp"
#include "a_magelightning.cpp"
#include "a_magestaff.cpp"
#include "a_pig.cpp"
#include "a_serpent.cpp"
#include "a_spike.cpp"
#include "a_summon.cpp"

View file

@ -1,107 +0,0 @@
/*
#include "actor.h"
#include "gi.h"
#include "m_random.h"
#include "s_sound.h"
#include "d_player.h"
#include "a_action.h"
#include "a_pickups.h"
#include "p_local.h"
#include "a_sharedglobal.h"
#include "p_enemy.h"
#include "d_event.h"
#include "gstrings.h"
#include "vm.h"
*/
static FRandom pr_snoutattack ("SnoutAttack");
static FRandom pr_pigattack ("PigAttack");
static FRandom pr_pigplayerthink ("PigPlayerThink");
// Pig player ---------------------------------------------------------------
class APigPlayer : public APlayerPawn
{
DECLARE_CLASS (APigPlayer, APlayerPawn)
public:
void MorphPlayerThink ();
};
IMPLEMENT_CLASS(APigPlayer, false, false, false, false)
void APigPlayer::MorphPlayerThink ()
{
if (player->morphTics & 15)
{
return;
}
if(Vel.X == 0 && Vel.Y == 0 && pr_pigplayerthink() < 64)
{ // Snout sniff
if (player->ReadyWeapon != nullptr)
{
P_SetPsprite(player, PSP_WEAPON, player->ReadyWeapon->FindState("Grunt"));
}
S_Sound (this, CHAN_VOICE, "PigActive1", 1, ATTN_NORM); // snort
return;
}
if (pr_pigplayerthink() < 48)
{
S_Sound (this, CHAN_VOICE, "PigActive", 1, ATTN_NORM);
}
}
//============================================================================
//
// A_SnoutAttack
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_SnoutAttack)
{
PARAM_ACTION_PROLOGUE(AActor);
DAngle angle;
int damage;
DAngle slope;
player_t *player;
AActor *puff;
FTranslatedLineTarget t;
if (NULL == (player = self->player))
{
return 0;
}
damage = 3+(pr_snoutattack()&3);
angle = player->mo->Angles.Yaw;
slope = P_AimLineAttack(player->mo, angle, MELEERANGE);
puff = P_LineAttack(player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, "SnoutPuff", true, &t);
S_Sound(player->mo, CHAN_VOICE, "PigActive", 1, ATTN_NORM);
if(t.linetarget)
{
AdjustPlayerAngle(player->mo, &t);
if(puff != NULL)
{ // Bit something
S_Sound(player->mo, CHAN_VOICE, "PigAttack", 1, ATTN_NORM);
}
}
return 0;
}
//============================================================================
//
// A_PigPain
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_PigPain)
{
PARAM_SELF_PROLOGUE(AActor);
CALL_ACTION(A_Pain, self);
if (self->Z() <= self->floorz)
{
self->Vel.Z = 3.5;
}
return 0;
}

View file

@ -109,8 +109,29 @@ IMPLEMENT_POINTERS_END
void DPSprite::InitNativeFields()
{
auto meta = RUNTIME_CLASS(DPSprite);
PType *TypeActor = NewPointer(RUNTIME_CLASS(AActor));
PType *TypePSP = NewPointer(RUNTIME_CLASS(DPSprite));
PType *TypePlayer = NewPointer(NewNativeStruct("Player", nullptr));
meta->AddNativeField("State", TypeState, myoffsetof(DPSprite, State), VARF_ReadOnly);
meta->AddNativeField("Caller", TypeActor, myoffsetof(DPSprite, Caller), VARF_ReadOnly);
meta->AddNativeField("Next", TypePSP, myoffsetof(DPSprite, Next), VARF_ReadOnly);
meta->AddNativeField("Owner", TypePlayer, myoffsetof(DPSprite, Owner), VARF_ReadOnly);
meta->AddNativeField("Sprite", TypeSpriteID, myoffsetof(DPSprite, Sprite));
meta->AddNativeField("Frame", TypeSInt32, myoffsetof(DPSprite, Frame));
meta->AddNativeField("ID", TypePlayer, myoffsetof(DPSprite, ID), VARF_ReadOnly);
meta->AddNativeField("processPending", TypeBool, myoffsetof(DPSprite, processPending));
meta->AddNativeField("x", TypeFloat64, myoffsetof(DPSprite, x));
meta->AddNativeField("y", TypeFloat64, myoffsetof(DPSprite, y));
meta->AddNativeField("oldx", TypeFloat64, myoffsetof(DPSprite, oldx));
meta->AddNativeField("oldy", TypeFloat64, myoffsetof(DPSprite, oldy));
meta->AddNativeField("firstTic", TypeBool, myoffsetof(DPSprite, firstTic));
meta->AddNativeField("Tics", TypeSInt32, myoffsetof(DPSprite, Tics));
meta->AddNativeField("bAddWeapon", TypeSInt32, myoffsetof(DPSprite, Flags), 0, PSPF_ADDWEAPON);
meta->AddNativeField("bAddBob", TypeSInt32, myoffsetof(DPSprite, Flags), 0, PSPF_ADDBOB);
meta->AddNativeField("bPowDouble", TypeSInt32, myoffsetof(DPSprite, Flags), 0, PSPF_POWDOUBLE);
meta->AddNativeField("bCVarFast", TypeSInt32, myoffsetof(DPSprite, Flags), 0, PSPF_CVARFAST);
meta->AddNativeField("bFlip", TypeSInt32, myoffsetof(DPSprite, Flags), 0, PSPF_FLIP);
}
//------------------------------------------------------------------------
@ -179,6 +200,14 @@ DPSprite *player_t::FindPSprite(int layer)
return pspr;
}
DEFINE_ACTION_FUNCTION(_Player, FindPSprite) // the underscore is needed to get past the name mangler which removes the first clas name character to match the class representation (needs to be fixed in a later commit)
{
PARAM_SELF_STRUCT_PROLOGUE(player_t);
PARAM_INT(id);
ACTION_RETURN_OBJECT(self->FindPSprite((PSPLayers)id));
}
//------------------------------------------------------------------------
//
//

View file

@ -161,6 +161,12 @@ bool ValidatePlayerClass(PClassActor *ti, const char *name)
return true;
}
void APlayerPawn::InitNativeFields()
{
auto meta = RUNTIME_CLASS(APlayerPawn);
meta->AddNativeField("JumpZ", TypeFloat64, myoffsetof(APlayerPawn, JumpZ));
}
void SetupPlayerClasses ()
{
FPlayerClass newclass;
@ -622,7 +628,7 @@ void player_t::SendPitchLimits() const
//
//===========================================================================
IMPLEMENT_CLASS(APlayerPawn, false, true, false, true)
IMPLEMENT_CLASS(APlayerPawn, false, true, true, true)
IMPLEMENT_POINTERS_START(APlayerPawn)
IMPLEMENT_POINTER(InvFirst)
@ -1381,6 +1387,10 @@ void APlayerPawn::GiveDefaultInventory ()
void APlayerPawn::MorphPlayerThink ()
{
VINDEX(APlayerPawn, MorphPlayerThink);
VMValue params[1] = { (DObject*)this };
VMFrameStack stack;
stack.Call(VFUNC, params, 1, nullptr, 0, nullptr);
}
void APlayerPawn::ActivateMorphWeapon ()

View file

@ -2543,7 +2543,15 @@ FxExpression *FxAddSub::Resolve(FCompileContext& ctx)
return nullptr;
}
if (left->IsVector() && right->IsVector())
if (left->ValueType == TypeState && right->IsInteger() && Operator == '+' && !left->isConstant())
{
// This is the only special case of pointer addition that will be accepted - because it is used quite often in the existing game code.
ValueType = TypeState;
right = new FxMulDiv('*', right, new FxConstant((int)sizeof(FState), ScriptPosition)); // multiply by size here, so that constants can be better optimized.
right = right->Resolve(ctx);
ABORT(right);
}
else if (left->IsVector() && right->IsVector())
{
// a vector2 can be added to or subtracted from a vector 3 but it needs to be the right operand.
if (left->ValueType == right->ValueType || (left->ValueType == TypeVector3 && right->ValueType == TypeVector2))
@ -2616,6 +2624,16 @@ ExpEmit FxAddSub::Emit(VMFunctionBuilder *build)
ExpEmit op2 = right->Emit(build);
if (Operator == '+')
{
if (op1.RegType == REGT_POINTER)
{
assert(!op1.Konst);
assert(op2.RegType == REGT_INT);
op1.Free(build);
op2.Free(build);
ExpEmit opout(build, REGT_POINTER);
build->Emit(op2.Konst? OP_ADDA_RK : OP_ADDA_RR, opout.RegNum, op1.RegNum, op2.RegNum);
return opout;
}
// Since addition is commutative, only the second operand may be a constant.
if (op1.Konst)
{