August 10, 2006 (Changes by Graf Zahl)

- Fixed: CheckActorInventory stored the return value in the wrong address
  on the ACS stack.
- Fixed: Skin sounds weren't properly restored after a SNDINFO reset.
- Added a more flexible ACS ChangeLevel function. It gets passed a level name
  instead of a level number and has several additional options (e.g. changing
  skill, starting the map without monsters and clearing the players' inventories. (UNTESTED!)
- Changed Thing_Activate so that passing a tid of 0 activates the calling actor.
- Changed Thing_Remove so that passing a tid of 0 removes the calling actor.
- Added DECORATE parameters to A_Saw.

SVN r283 (trunk)
This commit is contained in:
Christoph Oelckers 2006-08-10 15:28:12 +00:00
parent 2b0fa809c6
commit 688476b9aa
12 changed files with 176 additions and 49 deletions

View file

@ -1,3 +1,16 @@
August 10, 2006 (Changes by Graf Zahl)
- Fixed: CheckActorInventory stored the return value in the wrong address
on the ACS stack.
- Fixed: Skin sounds weren't properly restored after a SNDINFO reset.
August 6, 2006 (Changes by Graf Zahl)
- Added a more flexible ACS ChangeLevel function. It gets passed a level name
instead of a level number and has several additional options (e.g. changing
skill, starting the map without monsters and clearing the players' inventories.
- Changed Thing_Activate so that passing a tid of 0 activates the calling actor.
- Changed Thing_Remove so that passing a tid of 0 removes the calling actor.
- Added DECORATE parameters to A_Saw.
August 2, 2006
- Fixed: The ACS VM made no checks for object files without strings, assuming
that if it didn't have any strings, then it didn't matter what it calculated

View file

@ -241,8 +241,12 @@ END_DEFAULTS
void A_Saw (AActor *actor)
{
angle_t angle;
int damage;
int damage=0;
player_t *player;
int fullsound;
int hitsound;
const PClass * pufftype = NULL;
if (NULL == (player = actor->player))
{
@ -256,25 +260,37 @@ void A_Saw (AActor *actor)
return;
}
damage = 2 * (pr_saw()%10+1);
int index = CheckIndex (4, NULL);
if (index >= 0)
{
fullsound = StateParameters[index];
hitsound = StateParameters[index+1];
damage = EvalExpressionI (StateParameters[index+2], actor);
pufftype = PClass::FindClass ((ENamedName)StateParameters[index+3]);
}
else
{
fullsound = S_FindSound("weapons/sawfull");
hitsound = S_FindSound("weapons/sawhit");
}
if (pufftype == NULL) pufftype = RUNTIME_CLASS(ABulletPuff);
if (damage == 0) damage = 2;
damage *= (pr_saw()%10+1);
angle = actor->angle;
angle += pr_saw.Random2() << 18;
// use meleerange + 1 so the puff doesn't skip the flash
// [RH] What I think that really means is that they want the puff to show
// up on walls. If the distance to P_LineAttack is <= MELEERANGE, then it
// won't puff the wall, which is why the fist does not create puffs on
// the walls.
// use meleerange + 1 so the puff doesn't skip the flash (i.e. plays all states)
P_LineAttack (actor, angle, MELEERANGE+1,
P_AimLineAttack (actor, angle, MELEERANGE+1), damage,
MOD_UNKNOWN, RUNTIME_CLASS(ABulletPuff));
MOD_UNKNOWN, pufftype);
if (!linetarget)
{
S_Sound (actor, CHAN_WEAPON, "weapons/sawfull", 1, ATTN_NORM);
S_SoundID (actor, CHAN_WEAPON, fullsound, 1, ATTN_NORM);
return;
}
S_Sound (actor, CHAN_WEAPON, "weapons/sawhit", 1, ATTN_NORM);
S_SoundID (actor, CHAN_WEAPON, hitsound, 1, ATTN_NORM);
// turn to face target
angle = R_PointToAngle2 (actor->x, actor->y,

View file

@ -1034,7 +1034,7 @@ void G_Ticker ()
// G_PlayerFinishLevel
// Called when a player completes a level.
//
void G_PlayerFinishLevel (int player, EFinishLevelType mode)
void G_PlayerFinishLevel (int player, EFinishLevelType mode, bool resetinventory)
{
AInventory *item, *next;
player_t *p;
@ -1102,6 +1102,32 @@ void G_PlayerFinishLevel (int player, EFinishLevelType mode)
{ // Undo morph
P_UndoPlayerMorph (p, true);
}
// Clears the entire inventory and gives back the defaults for starting a game
if (resetinventory)
{
AInventory *inv = p->mo->Inventory;
while (inv != NULL)
{
AInventory *next = inv->Inventory;
if (!(inv->ItemFlags & IF_UNDROPPABLE))
{
inv->Destroy ();
}
else if (inv->GetClass() == RUNTIME_CLASS(AHexenArmor))
{
AHexenArmor *harmor = static_cast<AHexenArmor *> (inv);
harmor->Slots[3] = harmor->Slots[2] = harmor->Slots[1] = harmor->Slots[0] = 0;
}
inv = next;
}
p->ReadyWeapon = NULL;
p->PendingWeapon = WP_NOCHANGE;
p->psprites[ps_weapon].state = NULL;
p->psprites[ps_flash].state = NULL;
p->mo->GiveDefaultInventory();
}
}

View file

@ -72,7 +72,7 @@ enum EFinishLevelType
FINISH_NoHub
};
void G_PlayerFinishLevel (int player, EFinishLevelType mode);
void G_PlayerFinishLevel (int player, EFinishLevelType mode, bool resetinventory);
// Adds pitch to consoleplayer's viewpitch and clamps it
void G_AddViewPitch (int look);

View file

@ -1559,11 +1559,13 @@ BOOL secretexit;
static int startpos; // [RH] Support for multiple starts per level
extern BOOL NoWipe; // [RH] Don't wipe when travelling in hubs
static bool startkeepfacing; // [RH] Support for keeping your facing angle
static bool resetinventory; // Reset the inventory to the player's default for the next level
// [RH] The position parameter to these next three functions should
// match the first parameter of the single player start spots
// that should appear in the next map.
static void goOn (int position, bool keepFacing, bool secret)
static void goOn (int position, bool keepFacing, bool secret, bool resetinv)
{
static bool unloading;
@ -1580,6 +1582,8 @@ static void goOn (int position, bool keepFacing, bool secret)
startkeepfacing = keepFacing;
gameaction = ga_completed;
secretexit = secret;
resetinventory = resetinv;
bglobal.End(); //Added by MC:
// [RH] Give scripts a chance to do something
@ -1603,7 +1607,7 @@ static void goOn (int position, bool keepFacing, bool secret)
void G_ExitLevel (int position, bool keepFacing)
{
goOn (position, keepFacing, false);
goOn (position, keepFacing, false, false);
}
// Here's for the german edition.
@ -1612,7 +1616,23 @@ void G_SecretExitLevel (int position)
// [RH] Check for secret levels is done in
// G_DoCompleted()
goOn (position, false, true);
goOn (position, false, true, false);
}
void G_ChangeLevel(const char * levelname, int position, bool keepFacing, int nextSkill,
bool nointermission, bool resetinventory, bool nomonsters)
{
strncpy (level.nextmap, levelname, 8);
level.nextmap[8] = 0;
if (nextSkill != -1) NextSkill = nextSkill;
if (!nomonsters) dmflags = dmflags & ~DF_NO_MONSTERS;
else dmflags = dmflags | DF_NO_MONSTERS;
if (nointermission) level.flags |= LEVEL_NOINTERMISSION;
goOn(position, keepFacing, false, resetinventory);
}
void G_DoCompleted (void)
@ -1738,7 +1758,7 @@ void G_DoCompleted (void)
{
if (playeringame[i])
{ // take away appropriate inventory
G_PlayerFinishLevel (i, mode);
G_PlayerFinishLevel (i, mode, resetinventory);
}
}

View file

@ -301,6 +301,10 @@ void G_DeferedInitNew (char *mapname);
void G_ExitLevel (int position, bool keepFacing);
void G_SecretExitLevel (int position);
void G_ChangeLevel(const char * levelname, int position, bool keepFacing, int nextSkill,
bool showintermission, bool resetinventory, bool nomonsters);
void G_SetForEndGame (char *nextmap);
void G_StartTravel ();

View file

@ -4176,7 +4176,7 @@ int DLevelScript::RunScript ()
break;
case PCD_CHECKACTORINVENTORY:
STACK(1) = CheckInventory (SingleActorFromTID(STACK(2), NULL),
STACK(2) = CheckInventory (SingleActorFromTID(STACK(2), NULL),
FBehavior::StaticLookupString (STACK(1)));
sp--;
break;
@ -4887,6 +4887,17 @@ int DLevelScript::RunScript ()
}
}
sp -= 1;
case PCD_CHANGELEVEL:
{
int flags = STACK(2);
G_ChangeLevel(FBehavior::StaticLookupString(STACK(4)), STACK(3),
!!(flags & CHANGELEVEL_KEEPFACING), STACK(1),
!!(flags & CHANGELEVEL_NOINTERMISSION),
!!(flags & CHANGELEVEL_RESETINVENTORY),
!!(flags & CHANGELEVEL_NOMONSTERS));
sp -= 4;
}
break;
}

View file

@ -532,6 +532,7 @@ public:
PCD_RSGLOBALARRAY,
//[MW] end my p-codes
PCD_GETPLAYERINFO, // [GRB]
PCD_CHANGELEVEL,
PCODE_COMMAND_COUNT
};
@ -611,6 +612,16 @@ public:
SCRIPT_ModulusBy0,
};
enum
{
CHANGELEVEL_KEEPFACING = 1,
CHANGELEVEL_RESETINVENTORY = 2,
CHANGELEVEL_NOMONSTERS = 4,
CHANGELEVEL_CHANGESKILL = 8,
CHANGELEVEL_NOINTERMISSION = 16
};
DLevelScript (AActor *who, line_t *where, int num, const ScriptPtr *code, FBehavior *module,
bool backSide, int arg0, int arg1, int arg2, int always, bool delay);
~DLevelScript ();

View file

@ -983,22 +983,31 @@ FUNC(LS_HealThing)
FUNC(LS_Thing_Activate)
// Thing_Activate (tid)
{
AActor *actor;
FActorIterator iterator (arg0);
int count = 0;
actor = iterator.Next ();
while (actor)
if (arg0 != 0)
{
// Actor might remove itself as part of activation, so get next
// one before activating it.
AActor *temp = iterator.Next ();
actor->Activate (it);
actor = temp;
count++;
}
AActor *actor;
FActorIterator iterator (arg0);
int count = 0;
return count != 0;
actor = iterator.Next ();
while (actor)
{
// Actor might remove itself as part of activation, so get next
// one before activating it.
AActor *temp = iterator.Next ();
actor->Activate (it);
actor = temp;
count++;
}
return count != 0;
}
else if (it != NULL)
{
it->Activate(it);
return true;
}
return false;
}
FUNC(LS_Thing_Deactivate)
@ -1022,26 +1031,38 @@ FUNC(LS_Thing_Deactivate)
return count != 0;
}
static void RemoveThing(AActor * actor)
{
// Don't remove live players.
if (actor->player == NULL || actor != actor->player->mo)
{
// be friendly to the level statistics. ;)
if (actor->CountsAsKill() && actor->health > 0) level.total_monsters--;
if (actor->flags&MF_COUNTITEM) level.total_items--;
actor->Destroy ();
}
}
FUNC(LS_Thing_Remove)
// Thing_Remove (tid)
{
FActorIterator iterator (arg0);
AActor *actor;
actor = iterator.Next ();
while (actor)
if (arg0 != 0)
{
AActor *temp = iterator.Next ();
FActorIterator iterator (arg0);
AActor *actor;
// Don't remove live players.
if (actor->player == NULL || actor != actor->player->mo)
actor = iterator.Next ();
while (actor)
{
// be friendly to the level statistics. ;)
if (actor->CountsAsKill() && actor->health > 0) level.total_monsters--;
if (actor->flags&MF_COUNTITEM) level.total_items--;
actor->Destroy ();
AActor *temp = iterator.Next ();
RemoveThing(actor);
actor = temp;
}
actor = temp;
}
else if (it != NULL)
{
RemoveThing(it);
}
return true;

View file

@ -574,11 +574,11 @@ void R_InitSkins (void)
if (stricmp (key, "*pain") == 0)
{ // Replace all pain sounds in one go
aliasid = S_AddPlayerSound (skins[i].name, skins[i].gender,
playersoundrefs[0], lump);
playersoundrefs[0], lump, true);
for (int l = 3; l > 0; --l)
{
S_AddPlayerSoundExisting (skins[i].name, skins[i].gender,
playersoundrefs[l], aliasid);
playersoundrefs[l], aliasid, true);
}
}
else
@ -586,7 +586,7 @@ void R_InitSkins (void)
int sndref = S_FindSoundNoHash (key);
if (sndref != 0)
{
S_AddPlayerSound (skins[i].name, skins[i].gender, sndref, lump);
S_AddPlayerSound (skins[i].name, skins[i].gender, sndref, lump, true);
}
}
}

View file

@ -145,7 +145,7 @@ struct FMusicVolume
// This is used to recreate the skin sounds after reloading SNDINFO due to a changed local one.
struct FSavedPlayerSoundInfo
{
const char * pclass;
FName pclass;
int gender;
int refid;
int lumpnum;
@ -523,6 +523,8 @@ int S_AddPlayerSound (const char *pclass, int gender, int refid, int lumpnum, bo
PlayerSounds[soundlist + S_sfx[refid].link] = id;
Printf("Player sound %s: Classnum %d Gender %d, Refid %d, Lump %d, fromskin %d\n", pclass, classnum, gender, refid, lumpnum, fromskin);
if (fromskin) S_SavePlayerSound(pclass, gender, refid, lumpnum, false);
return id;
@ -543,6 +545,9 @@ int S_AddPlayerSoundExisting (const char *pclass, int gender, int refid,
PlayerSounds[soundlist + S_sfx[refid].link] = aliasto;
Printf("Player alias %s: Classnum %d Gender %d, Refid %d, Aliasto %d, fromskin %d\n", pclass, classnum, gender, refid, aliasto, fromskin);
if (fromskin) S_SavePlayerSound(pclass, gender, refid, aliasto, true);
return aliasto;

View file

@ -645,7 +645,7 @@ AFuncDesc AFTable[]=
FUNC(A_Punch, NULL)
FUNC(A_CheckReload, NULL)
FUNC(A_GunFlash, NULL)
FUNC(A_Saw, NULL)
FUNC(A_Saw, "ssxm")
// DECORATE specific functions
FUNC(A_BulletAttack, NULL)