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 August 2, 2006
- Fixed: The ACS VM made no checks for object files without strings, assuming - 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 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) void A_Saw (AActor *actor)
{ {
angle_t angle; angle_t angle;
int damage; int damage=0;
player_t *player; player_t *player;
int fullsound;
int hitsound;
const PClass * pufftype = NULL;
if (NULL == (player = actor->player)) if (NULL == (player = actor->player))
{ {
@ -256,25 +260,37 @@ void A_Saw (AActor *actor)
return; 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 = actor->angle;
angle += pr_saw.Random2() << 18; angle += pr_saw.Random2() << 18;
// use meleerange + 1 so the puff doesn't skip the flash // use meleerange + 1 so the puff doesn't skip the flash (i.e. plays all states)
// [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.
P_LineAttack (actor, angle, MELEERANGE+1, P_LineAttack (actor, angle, MELEERANGE+1,
P_AimLineAttack (actor, angle, MELEERANGE+1), damage, P_AimLineAttack (actor, angle, MELEERANGE+1), damage,
MOD_UNKNOWN, RUNTIME_CLASS(ABulletPuff)); MOD_UNKNOWN, pufftype);
if (!linetarget) if (!linetarget)
{ {
S_Sound (actor, CHAN_WEAPON, "weapons/sawfull", 1, ATTN_NORM); S_SoundID (actor, CHAN_WEAPON, fullsound, 1, ATTN_NORM);
return; return;
} }
S_Sound (actor, CHAN_WEAPON, "weapons/sawhit", 1, ATTN_NORM); S_SoundID (actor, CHAN_WEAPON, hitsound, 1, ATTN_NORM);
// turn to face target // turn to face target
angle = R_PointToAngle2 (actor->x, actor->y, angle = R_PointToAngle2 (actor->x, actor->y,

View file

@ -1034,7 +1034,7 @@ void G_Ticker ()
// G_PlayerFinishLevel // G_PlayerFinishLevel
// Called when a player completes a level. // 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; AInventory *item, *next;
player_t *p; player_t *p;
@ -1102,6 +1102,32 @@ void G_PlayerFinishLevel (int player, EFinishLevelType mode)
{ // Undo morph { // Undo morph
P_UndoPlayerMorph (p, true); 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 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 // Adds pitch to consoleplayer's viewpitch and clamps it
void G_AddViewPitch (int look); void G_AddViewPitch (int look);

View file

@ -1559,11 +1559,13 @@ BOOL secretexit;
static int startpos; // [RH] Support for multiple starts per level static int startpos; // [RH] Support for multiple starts per level
extern BOOL NoWipe; // [RH] Don't wipe when travelling in hubs extern BOOL NoWipe; // [RH] Don't wipe when travelling in hubs
static bool startkeepfacing; // [RH] Support for keeping your facing angle 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 // [RH] The position parameter to these next three functions should
// match the first parameter of the single player start spots // match the first parameter of the single player start spots
// that should appear in the next map. // 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; static bool unloading;
@ -1580,6 +1582,8 @@ static void goOn (int position, bool keepFacing, bool secret)
startkeepfacing = keepFacing; startkeepfacing = keepFacing;
gameaction = ga_completed; gameaction = ga_completed;
secretexit = secret; secretexit = secret;
resetinventory = resetinv;
bglobal.End(); //Added by MC: bglobal.End(); //Added by MC:
// [RH] Give scripts a chance to do something // [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) void G_ExitLevel (int position, bool keepFacing)
{ {
goOn (position, keepFacing, false); goOn (position, keepFacing, false, false);
} }
// Here's for the german edition. // Here's for the german edition.
@ -1612,7 +1616,23 @@ void G_SecretExitLevel (int position)
// [RH] Check for secret levels is done in // [RH] Check for secret levels is done in
// G_DoCompleted() // 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) void G_DoCompleted (void)
@ -1738,7 +1758,7 @@ void G_DoCompleted (void)
{ {
if (playeringame[i]) if (playeringame[i])
{ // take away appropriate inventory { // 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_ExitLevel (int position, bool keepFacing);
void G_SecretExitLevel (int position); 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_SetForEndGame (char *nextmap);
void G_StartTravel (); void G_StartTravel ();

View file

@ -4176,7 +4176,7 @@ int DLevelScript::RunScript ()
break; break;
case PCD_CHECKACTORINVENTORY: case PCD_CHECKACTORINVENTORY:
STACK(1) = CheckInventory (SingleActorFromTID(STACK(2), NULL), STACK(2) = CheckInventory (SingleActorFromTID(STACK(2), NULL),
FBehavior::StaticLookupString (STACK(1))); FBehavior::StaticLookupString (STACK(1)));
sp--; sp--;
break; break;
@ -4887,6 +4887,17 @@ int DLevelScript::RunScript ()
} }
} }
sp -= 1; 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; break;
} }

View file

@ -532,6 +532,7 @@ public:
PCD_RSGLOBALARRAY, PCD_RSGLOBALARRAY,
//[MW] end my p-codes //[MW] end my p-codes
PCD_GETPLAYERINFO, // [GRB] PCD_GETPLAYERINFO, // [GRB]
PCD_CHANGELEVEL,
PCODE_COMMAND_COUNT PCODE_COMMAND_COUNT
}; };
@ -611,6 +612,16 @@ public:
SCRIPT_ModulusBy0, 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, 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); bool backSide, int arg0, int arg1, int arg2, int always, bool delay);
~DLevelScript (); ~DLevelScript ();

View file

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

View file

@ -574,11 +574,11 @@ void R_InitSkins (void)
if (stricmp (key, "*pain") == 0) if (stricmp (key, "*pain") == 0)
{ // Replace all pain sounds in one go { // Replace all pain sounds in one go
aliasid = S_AddPlayerSound (skins[i].name, skins[i].gender, aliasid = S_AddPlayerSound (skins[i].name, skins[i].gender,
playersoundrefs[0], lump); playersoundrefs[0], lump, true);
for (int l = 3; l > 0; --l) for (int l = 3; l > 0; --l)
{ {
S_AddPlayerSoundExisting (skins[i].name, skins[i].gender, S_AddPlayerSoundExisting (skins[i].name, skins[i].gender,
playersoundrefs[l], aliasid); playersoundrefs[l], aliasid, true);
} }
} }
else else
@ -586,7 +586,7 @@ void R_InitSkins (void)
int sndref = S_FindSoundNoHash (key); int sndref = S_FindSoundNoHash (key);
if (sndref != 0) 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. // This is used to recreate the skin sounds after reloading SNDINFO due to a changed local one.
struct FSavedPlayerSoundInfo struct FSavedPlayerSoundInfo
{ {
const char * pclass; FName pclass;
int gender; int gender;
int refid; int refid;
int lumpnum; 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; 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); if (fromskin) S_SavePlayerSound(pclass, gender, refid, lumpnum, false);
return id; return id;
@ -543,6 +545,9 @@ int S_AddPlayerSoundExisting (const char *pclass, int gender, int refid,
PlayerSounds[soundlist + S_sfx[refid].link] = aliasto; 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); if (fromskin) S_SavePlayerSound(pclass, gender, refid, aliasto, true);
return aliasto; return aliasto;

View file

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