Sprites, textures, sounds, code, and other resources belong here. Share and share-alike!
Forum rules
Before posting your Resource, please make sure you can answer YES to any of the following questions:
Is the resource ENTIRELY my own work?
If no to the previous one, do I have permission from the original author?
If no to the previous one, did I put a reasonable amount of work into the resource myself, such that the changes are noticeably different from the source that I could take credit for them?
If you answered no to all three, maybe you should consider taking your stuff somewhere other than the Resources forum.
Inspired by this thread I decided to emulate the Sigil in DECORATE using no restricted functions nor inheriting from the Sigil actor itself. I've done the best that I could based on what I could interpret from the source code.
The ACS part, aside from one little script, is mostly to make this new, fake Sigil compatible with the game's stock maps and enemies (AlienSpectre5).
What I got in the end is a pretty accurate replica(I think).
[EDIT] Updated ACS code (Old version) with Nightfall's suggestions. [/EDIT]
*************************************
[EDIT2]So, yesterday I had an (rather bizzare, me thinks) idea. How about using the Sigil itself as a piece-counter for the fake Sigil? To be specific, why not use the native GetSigilPieces() function? From that came other strange ideas (about how to implement this)...and from brainstorming to realization I give you a new version. (I shall call it V1.1 )
Like I promised, it's a little less decorate and ACS code but it's a bit more hackish, IMO. And it's compatible. (even with the status bar!)
Basically, in this version the Sigil and the NNSigil are 'connected' so to speak. However, I realize that some of you may not like this new version. So I've left the older version just in case.
On a minor note, I have included Ed the Bat's corrections (slightly altered) in both versions to make it slightly more faithful to the original on a technical level.
On another minor note, thanks to a recent bugfix I've removed the 'Drop' actors in the 'Old version' and moved their 'Drop' state to the 'Pickup' actors, where it belongs.[/EDIT2]
[minor edit(3)]slightly reworded what was posted in EDIT2 to make myself more clear[/minor edit(3)]
*************************************
[EDIT4]Fixed some obscure bugs after reading this wonderful news. Well actually I first wanted to see if the A_Light# bug was still present(It wasn't ), but then discovered other unwanted problems.
1) When firing the fake Sigil while picking up another piece, the attack type would be that of the new piece amount instead of what it's supposed to be. Eg. if you have 3 pieces, fire it, then pickup another piece, you would shoot the tall, vertical lightning column instead of the spread shot. It would also change to represent four pieces without going through the "lowering and rising" animation.
This was fixed by moving/copying the following code from the 'Fire' state to the 'Fire1/2/3/4/5' states.
"----" A 0 A_PlaySound("weapons/sigilcharge", CHAN_WEAPON)
"----" A 18 Bright A_Light2
"----" A 3 Bright A_GunFlash
TNT1 A 0 A_PlaySound("weapons/sigilcharge", CHAN_WEAPON)
(Why on Earth didn't I realize this sooner. *sigh*)
2) It seems that, just like any actors, weapons will ignore the codepointer in the first frame in their 'Select' state ('Ready' state if the map has 'SpawnWithWeaponRaised' set) when transitioning maps.
Actually, it seems that weapons are a bit unique. If the first frame is 0 tics long (not sure about this bit) and if subsequent frames are 0-tic frames, all the codepointers (if any) will be ignored until there is a frame that is at least 1 tic long (not sure if the codepointer on that last frame will be ignored or not).
This bug was fixed earlier, but I decided to 'refix' it by duplicating the first A_Jump* function. This way when you switch maps it would ignore the first call, but it would act on the second, identical one. And switching weapons will not delay 'Select/Ready' by one tic before calling A_Raise/A_WeaponReady. (Now I'm being picky and a hypocrite )
3) In the 'New version', if you have the fake Sigil selected and if you entered a new map, or revisited a previous one in which the amount of pieces you had was different from the amount you have now, the fake Sigil would run it's upgrade animation hack when it's obviously not necessary. This one is really obscure because it only happened on maps that have 'SpawnWithWeaponRaised' set. Updated ACS code (New version). See the commentary there for relevant bits.
Spoiler: On a minor, completely irrelevant note
I've removed the first, commented-out 'Fire3' state since I realized that no one in their right mind would want to use it beyond testing since it seemed to cause a bit of lag (for me), while the second 'Fire3' is less of a clutter and more faithful to A_FireSigil3 in the way it positioned the projectiles when spawning them.
Specifically, A_FireSigil3 positioned the projectiles around the player, while 20 calls of A_FireCustomMissile (without changing the player's angle with A_SetAngle) positioned them right in front of your face, which is what caused the lag, I think.
This should be the last update since I pretty much consider this thing done.[/EDIT4]
#library "nnsigil"
#include "zcommon.acs"
Script "NNSigilDamageUser" (int damage)
{
Thing_Damage2(0, damage, "NNSigilUse");
}
//Ignore the rest below if you don't wish to make your sigil compatible with the stock maps.
Script "NNSigilSpectre5Death" (void)
{
if( ThingCountName("NNSigilSpectre5", 0) )
terminate;
//Find a player without messing with TIDs
bool PlayerFound = false;
//As suggested by Nightfall
for (int i = 0; i < 8; i++)
{
if ( PlayerInGame(i) )
{
SetActivator(0, AAPTR_PLAYER1 << i);
if ( GetActorProperty(0, APROP_Health) > 0)
{
PlayerFound = true;
break;
}
}
}
if( !PlayerFound )
terminate; //Either no player or (all) player(s) dead
Print(l:"TXT_KILLED_LOREMASTER");
GiveInventory("QuestItem26", 1);
if( GameType() == GAME_SINGLE_PLAYER )
{
GiveInventory("UpgradeStamina", 10);
GiveInventory("UpgradeAccuracy", 1);
}
bool HasCommUnit = CheckInventory("Communicator");
if ( !HasCommUnit )
GiveInventory("Communicator", 1);
//The main reason why this script is necessary
if( CheckInventory("NNSigil") && CheckInventory("NNSigilPiece") == 5 )
SendToCommunicator(85, 0, 0, 0); //Couldn't find another way to change the LOG (mission text)
else //and it's not a game breaker if the "incoming message"
SendToCommunicator(83, 0, 0, 0); //text is shown in the upper left corner, is it?
if ( !HasCommUnit )
TakeInventory("Communicator", 1);
Floor_LowerToLowest(666, 8);
}
//This is used to recognize the fake Sigil, It's based off of script 0.
//
//While I don't have much experience with xlat lumps,
//it seems that they don't recognize ACS_Named* specials.
Script 2000 (int type, int tag)
{
switch(type)
{
case 196:
if ( CheckInventory("NNSigil") && CheckInventory("NNSigilPiece") >= 2)
{
Floor_LowerToLowest(tag, 8);
ClearLineSpecial();
}
break;
case 197:
if ( CheckInventory("NNSigil") && CheckInventory("NNSigilPiece") >= 2)
{
Door_Close(tag, 64);
ClearLineSpecial();
}
break;
case 200:
if ( CheckInventory("NNSigil") )
{
Door_Open(tag, 16);
ClearLineSpecial();
}
break;
case 229:
SetResultValue(0);
if ( CheckInventory("NNSigil") && CheckInventory("NNSigilPiece") == 5)
SetResultValue( Door_Animated(tag, 4, 105) );
break;
case 235:
SetResultValue(0);
if ( CheckInventory("NNSigil") && CheckInventory("NNSigilPiece") == 5)
SetResultValue( Door_Open(tag, 8)|Floor_LowerToLowest(tag, 8) );
break;
}
}
//And now for some multiplayer related nonsense, bleh.
Script "NNSigilPlayerDeath" DEATH
{
if ( !(GetCVar("dmflags2") & 2) || !CheckWeapon("NNSigil") )
terminate;
//As suggested by Nightfall.
int piece = CheckInventory("NNSigilPiece");
if ( !piece ) piece = 1;
SpawnSpot( strparam(s:"NNSigil", d:piece, s:"Pickup"), 0 );
}
include "xlat/strife.txt"
196 = WALK|REP, ACS_ExecuteAlways(2000, 0, 196, tag)
197 = WALK|REP, ACS_ExecuteAlways(2000, 0, 197, tag)
200 = WALK, ACS_ExecuteAlways(2000, 0, 200, tag)
229 = USE|REP, ACS_ExecuteWithResult(2000, 229, tag)
235 = USE, ACS_ExecuteWithResult(2000, 235, tag)
// 197 was originally just WALK but that seems wrong.
// In vanilla, the Oracle would lock all exits when you
// return after killing the Bishop. That doesn't happen in ZDoom.
// Now it does :P
// And while this would be worthy as a bug report, it's not that relevant IMO.
#library "nnsigil"
#include "zcommon.acs"
Script "NNSigilDamageUser" (int damage)
{
Thing_Damage2(0, damage, "NNSigilUse");
}
Script "NNSigilPieceCount" (void)
{
SetResultValue( GetSigilPieces() );
}
bool monitoring_players[8];
bool players_returned[8];
Script "NNSigilMonitor" ENTER
{
int current_pieces;
int previous_pieces = GetSigilPieces(); //Takes care of first time visits
//(related to bug #3 mentioned in EDIT4)
int player = PlayerNumber();
if ( monitoring_players[player] ) //Make sure there's only one instance
terminate; //of this script running per player.
monitoring_players[player] = true; //(as some goof might try to puke this)
while( monitoring_players[player] )
{
players_returned[player] = false;
Delay(1);
if ( GetActorProperty(0, APROP_Health) <= 0 )
continue; //Don't terminate if dead (could be a COOP or DM game)
current_pieces = GetSigilPieces();
//If you find this next part undesirable, you can
//just put 'continue;' right after the 'if' statement.
if ( !current_pieces )
{
if ( CheckInventory("NNSigil") ) //If you don't have the real one
TakeInventory("NNSigil", 1); //you can't have the NN one
continue;
}
else if ( !CheckInventory("NNSigil") )
GiveInventory("NNSigil", 1);
if ( CheckWeapon("Sigil") )
{
SetWeapon("NNSigil");
continue;
}
if ( previous_pieces != current_pieces )
{
previous_pieces = current_pieces;
if ( players_returned[player] ) //Takes care of subsequent visits
continue; //(related to bug #3 mentioned in EDIT4)
if ( CheckWeapon("NNSigil") ) //Don't run upgrade animation hack
SetWeapon("Sigil"); //if player is holding another weapon.
}
}
}
Script "NNSigilStopMonitoring" (int player) DISCONNECT
{
monitoring_players[player] = false;
}
Script "NNSigilPlayerReturned" RETURN
{
players_returned[PlayerNumber()] = true;
}
//And now for some multiplayer related nonsense, bleh.
Script "NNSigilPlayerDeath" DEATH
{
if ( !(GetCVar("dmflags2") & 2) || !CheckWeapon("NNSigil") )
terminate;
int piece = GetSigilPieces();
if ( !piece ) piece = 1; //Shouldn't happen, but better safe than sorry
SpawnSpot( strparam(s:"Sigil", d:piece), 0 );
}
Spoiler: MAPINFO, for the sake of completeness (you don't really need it)
The reason why I post this here (in Resources) is because I want to see what people might do with the sigil since, I imagine, they get discouraged by realizing that you can't really do anything useful with it except maybe replace the projectiles. And also because I lack creativity, heh.
So yeah, this thing should pretty much behave like the real sigil. Copy-paste what you want and change to your liking. You don't have to give me credit if you don't care. Just do something crazy with it.
Dear moderators,
If you feel like this doesn't belong in Resources then please move it elsewhere. (I don't wish to be a nuisance.)
Last edited by Fishytza on Fri Jan 25, 2013 7:10 pm, edited 4 times in total.
One small error I spotted with NNSigilLightningSpot and NNSigilLightningBigV is that, when they call Goto Super::Spawn, they'll trigger the codepointers in the first frame of their parents' Spawn class, which doesn't happen in the original. This means A_CountDown or A_Tracer2 get called one time too early/often. You might want to tweak them thusly:
ACTOR NNSigilLightningSpot : SpectralLightningSpot
{
+SPECTRAL //This flag is needed, otherwise the SpectralLightningV1/V2
States //actors won't damage the spectres. Wierd.
{
Spawn:
TNT1 A 0
TNT1 A 0 A_TransferPointer(AAPTR_TARGET,AAPTR_DEFAULT,AAPTR_PLAYER_GETTARGET,AAPTR_TRACER)
TNT1 A 0 A_CheckFlag("SHOOTABLE","Enemy",AAPTR_TRACER)
TNT1 A 0 A_Warp(AAPTR_TARGET) //Try to stick to the player's feet.
TNT1 A 0 A_ChangeVelocity(28,0,0,CVF_RELATIVE|CVF_REPLACE)
ZAP5 A 4 BRIGHT
Goto Super::Spawn+1
Enemy:
TNT1 A 0 A_Warp(AAPTR_TRACER, 0,0,0, 0, WARPF_NOCHECKPOSITION|WARPF_STOP|WARPF_TOFLOOR)
ZAP5 A 4 BRIGHT
Goto Super::Spawn+1
}
}
Actor NNSigilLightningBigV : SpectralLightningBigV1
{
Decal "BaronScorch"
States
{
Spawn:
TNT1 A 0
TNT1 A 0 A_TransferPointer(AAPTR_TARGET, AAPTR_DEFAULT, AAPTR_PLAYER_GETTARGET, AAPTR_TRACER)
TNT1 A 0 A_CheckFlag("SHOOTABLE", "Super::Spawn", AAPTR_TRACER)
TNT1 A 0 A_ChangeVelocity(28,0,0, CVF_RELATIVE)
ZOT2 A 4 BRIGHT
Goto Super::Spawn+1
}
}
Basically, just add a dummy state before jumping to the parent, so simulate the effect of the first state after Spawning doing nothing.
I'm not that picky, Ed, but I'll consider it. Besides, I'm working on an alternative way for the upgrade animation hack, which is kinda similar to what you suggested, and something else.
If I get this done, which should take a day or two (unless something in my life gets in the way), it would cut down both the decorate and ACS code as well as make this compatible with the stock game, whether you care about compatibility or not