Commander Keen TC

Maps, modifications, add-ons, projects, and other releases for Zandronum. Also includes announcers.

Would you play Deathmatch?

 
Total votes: 0

Llewellyn
Forum Regular
Posts: 578
Joined: Mon Jul 02, 2012 7:12 am

Commander Keen TC

#1

Post by Llewellyn » Tue Jul 24, 2012 1:10 am

I've been busy lately making a Commander Keen TC for Zandronum.
I am trying to make it as authentic as possible, including physics, ledge grabbing, and individual sprites for just about every movement (jumping, falling, shooting up/down, etc.)
Right now I'm a good way through the mod.

Legal issues will probably keep me from releasing anything but a recreation of the Shareware version on the forums.

After I get the Shareware version maps complete, I plan to add some Deathmatch maps to the Shareware release, or make a separate Deathmatch version.

Obligatory screenshot(s):
Spoiler: Screenshot (Open)
Image
Also credits to IjonTichy for some ACS advice.

Since I already have all the sprites, maps, and music ripped the only thing I'm missing to be able to make it is the rest of the sound effects. Currently I only have the Death Sound, minor and major point pickup sounds. I used a utility to rip the sounds from the Exe into WAV sounds but they didn't come out right, so I think the only way to get them might be to record them manually. I would appreciate it if someone could help me with ripping the sound effects.

Here is an example of what Deathmatch would be like kinda.
Last edited by Llewellyn on Tue Jul 24, 2012 8:51 am, edited 1 time in total.

User avatar
Ivan
Addicted to Zandronum
Posts: 2229
Joined: Mon Jun 04, 2012 5:38 pm
Location: Omnipresent

RE: Commander Keen TC

#2

Post by Ivan » Wed Jul 25, 2012 10:49 am

This looks pretty nice actually, I say go for the DM, but be sure to add those funny skins in it :D
=== RAGNAROK DM ON ... uh... dead forever? ===
=== ALWAYS BET ON ... uh... dead forever? ===
=== Who wanta sum wang? ===
=== Death and Decay - A new Monster/Weapon replacer ===

Llewellyn
Forum Regular
Posts: 578
Joined: Mon Jul 02, 2012 7:12 am

RE: Commander Keen TC

#3

Post by Llewellyn » Wed Jul 25, 2012 11:12 am

Ivan wrote: This looks pretty nice actually, I say go for the DM, but be sure to add those funny skins in it :D
Thanks! I've run into a couple of bugs, but soon the "gameplay" will be feature complete and I'll be adding fun stuff to it, like maps, and Deathmatch, Singleplayer (in that order.)

Also, once I get it feature complete, bugfree, Deathmatch compatable with atleast 1 map, I'll release a version with a "how-to" mapping guide.
Last edited by Llewellyn on Wed Jul 25, 2012 11:25 am, edited 1 time in total.

User avatar
Ænima
Addicted to Zandronum
Posts: 3583
Joined: Tue Jun 05, 2012 6:12 pm

RE: Commander Keen TC

#4

Post by Ænima » Wed Jul 25, 2012 11:19 am

HOLY DAMN. That looks like it required a LOT of work.


I think TheMisterCat was working on a Keen mod too. Maybe ask if he wants to help. :p
Reinforcements: midgame Survival joining/respawning
Doom64: Unabsolved: Doom64 + Diablo II
ZandroSkins: a pack made by our community
AeniPuffs: 3D blood and bullet puff effects, free to use for your own mods
Squad Radio: a WASD-based radio chat menu, add your own custom sounds!
Mercenaries (on hold)
Image

Llewellyn
Forum Regular
Posts: 578
Joined: Mon Jul 02, 2012 7:12 am

RE: Commander Keen TC

#5

Post by Llewellyn » Wed Jul 25, 2012 11:25 am

Heres a quick look on what mapping is like, its actually a lot easier than mapping for other maps, with one exception, you have to make the wall into one texture using patches and the TextureX (Textures or Texture2) lump. I am currently debating whether to animate any of the textures to make them look like the original, as this would double the texture work required.
Spoiler: LargeImage (Open)
Image

Top right is a screenshot from in the original game. Bottom is In Zandronum. Top is Doom Builder 3D mode (not GZDoom addon) and middle is 2D mode.
As you can see in the 2D mode, the map is just made of one area. The area consists of 3D floors, things, and one sidedef texture. Some maps have more than one area though. (Including this one, but until its more than just a test map it will be one area :P)

Ænima wrote: I think TheMisterCat was working on a Keen mod too. Maybe ask if he wants to help. :p
The only way anyone can help me right now is to rip some sounds or give me Decorate/ACS advice when I need it... the mod has already gotten too complicated to try and share. My ACS (uncompiled) is over 2000 lines. My Decorate is 1232. I've managed to keep the ACS from becoming spaghetti code by #defining and commenting almoast everything, but it still is very interdependent on itself and it takes ME half a minute to find the particular piece of code I need to change when I make an error.
Last edited by Llewellyn on Wed Jul 25, 2012 11:31 am, edited 1 time in total.

one_Two
Addicted to Zandronum
Posts: 1753
Joined: Thu Jun 07, 2012 4:47 pm

RE: Commander Keen TC

#6

Post by one_Two » Wed Jul 25, 2012 11:31 am

Looks brilliant, can't tell it's a 3d engine at all.

Llewellyn
Forum Regular
Posts: 578
Joined: Mon Jul 02, 2012 7:12 am

RE: Commander Keen TC

#7

Post by Llewellyn » Wed Jul 25, 2012 11:32 am

one_Two wrote: Looks brilliant, can't tell it's a 3d engine at all.
You can a little bit if you look at the rocks when you walk by them, because they're actually offset from the wall by 1px. But it actually gives it a cool look IMO because it looks closer (in the foreground rather than middle or background, like intended.)

I plan on keeping Singleplayer as authentic as possible, but I will probably go batshit crazy in DM (and let other people do so too!)

I wanna try LMS with this so badly now.
Last edited by Llewellyn on Wed Jul 25, 2012 11:34 am, edited 1 time in total.

TheMisterCat
 
Posts: 79
Joined: Mon Jun 04, 2012 2:21 pm
Location: NZ

RE: Commander Keen TC

#8

Post by TheMisterCat » Thu Jul 26, 2012 3:12 am


Llewellyn
Forum Regular
Posts: 578
Joined: Mon Jul 02, 2012 7:12 am

RE: Commander Keen TC

#9

Post by Llewellyn » Thu Jul 26, 2012 4:11 am

THat looks really nice.
You have the sounds and enemy AI, things I still need >:D
(Also how did you do the pogostick, just curious)
Last edited by Llewellyn on Thu Jul 26, 2012 4:12 am, edited 1 time in total.

TheMisterCat
 
Posts: 79
Joined: Mon Jun 04, 2012 2:21 pm
Location: NZ

RE: Commander Keen TC

#10

Post by TheMisterCat » Fri Jul 27, 2012 3:16 am

i'll post the decorate and ACS when I get home from work

Watermelon
Zandrone
Posts: 1244
Joined: Thu Jun 28, 2012 9:07 pm
Location: Rwanda

RE: Commander Keen TC

#11

Post by Watermelon » Fri Jul 27, 2012 6:09 am

Keep up the awesome work! This would be so fun to play

TheMisterCat
 
Posts: 79
Joined: Mon Jun 04, 2012 2:21 pm
Location: NZ

RE: Commander Keen TC

#12

Post by TheMisterCat » Fri Jul 27, 2012 7:52 am

Here is the entirety of the ACS, commented for the most part

Code: Select all

#include "zcommon.acs"

int LVL_YPOS = 96.0;          // Force all actors along this plane

bool YSuspend[32];            // Suspend Y-axis forcing array for players
bool Pogo[32];                   // Is pogo active?
bool PogoFirst[32];            // Is this the first pogo use? (animation related)
int DownBuffer[32];            // Camera looking buffer for pressing down
int DownFirst[32];              // checks against buffer
int UpBuffer[32];                // Camera looking buffer for pressing up
int UpFirst[32];                  // checks against buffer
int ModY[32];                    // Camera distance Y
int ModZ[32];                    // Camera height
int Angle[32];                    // Player facing direction

// Called by DECORATE to check if a player is pressing jump

Script 2 (VOID)
{
    int IsJumping = GetPlayerInput(-1, INPUT_BUTTONS);
    
        if(IsJumping & BT_JUMP)
                SetResultValue(60);
        else
                SetResultValue(36);
}

Script 1 ENTER
{
Spawn("GameCamera", 0, 0, 0, 100+PlayerNumber(), 64);
Thing_ChangeTid(0, 500+PlayerNumber());
ChangeCamera(100+PlayerNumber(), 0, 0);
ACS_Execute(3, 0, PlayerNumber());
}


// This forcibly respawns monsters when the player dies, instead of having the map reload.
Script 998 RESPAWN
{
Thing_Remove(1801);
SetActorState(1800, "Respawn");
Thing_Remove(100+PlayerNumber());
Spawn("GameCamera", 0, 0, 0, 100+PlayerNumber(), 64);
Thing_ChangeTid(0, 500+PlayerNumber());
ChangeCamera(100+PlayerNumber(), 0, 0);
ACS_Execute(3, 0, PlayerNumber());
SetActorState(1800, "Respawn");
}   

SCRIPT 997 DEATH
{
Thing_ChangeTid(0, 0);
}


// This script allows the player to look up and down with the camera by holding the respective controls, 
// which increases the Up/DownBuffer array.

Script 3 (int PlayNum)
{
SetActivator(500+PlayNum);
while(GetActorProperty(0, APROP_HEALTH) > 0)
    {
int x = GetActorX(0);
int z = GetActorZ(0);
int vx = GetActorVelX(0);
int vz = GetActorVelZ(0);
int cx = GetActorX(100+PlayerNumber());
int cz = GetActorZ(100+PlayerNumber());
ModY[PlayerNumber()] = -256.0;  	

        	int Input = GetPlayerInput(0, INPUT_BUTTONS);
        
            	if(Input & BT_MOVELEFT)
	                { Angle[PlayerNumber()] = 0.5; ModZ[PlayerNumber()] = 32.0;
                        DownFirst[PlayerNumber()] = False; 
                        UpFirst[PlayerNumber()] = False;
                            DownBuffer[PlayerNumber()] = 0;
                            UpBuffer[PlayerNumber()] = 0; }
       	else if(Input & BT_MOVERIGHT)
                	{ Angle[PlayerNumber()] = 1.0; ModZ[PlayerNumber()] = 32.0;
                        DownFirst[PlayerNumber()] = False; 
                        UpFirst[PlayerNumber()] = False;
                            DownBuffer[PlayerNumber()] = 0;
                            UpBuffer[PlayerNumber()] = 0; }

        	if(GetActorY(0) != LVL_YPOS && YSuspend[PlayerNumber()] == False)
	            SetActorPosition(0, GetActorX(500+PlayerNumber()), 			
                    LVL_YPOS, GetActorZ(500+PlayerNumber()), 0);

       SetActorAngle(0, Angle[PlayerNumber()]);
 
    if(Input & BT_LOOKUP && Pogo[PlayerNumber()] == False 
            && GetActorProperty(0, APROP_HEALTH) > 0)
                UpBuffer[PlayerNumber()]++; 
 
    if(Input & BT_LOOKDOWN && Pogo[PlayerNumber()] == False
            && GetActorProperty(0, APROP_HEALTH) > 0)
                DownBuffer[PlayerNumber()]++;

    if(DownBuffer[PlayerNumber()] > 55)
        {
            if(DownFirst[PlayerNumber()] == False)
                {
                    SetActorState(0, "LookDown", 0);
                    DownFirst[PlayerNumber()] = True;
                    ModZ[PlayerNumber()] = 0;
                }
			
            if(ModZ[PlayerNumber()] > -96.0)
                ModZ[PlayerNumber()] -= 4.0;
         }
         
    if(UpBuffer[PlayerNumber()] > 55)
        {
            if(UpFirst[PlayerNumber()] == False)
                {
                    SetActorState(0, "LookUp", 0);
                    UpFirst[PlayerNumber()] = True;
                    ModZ[PlayerNumber()] = 0;
                }
			
            if(ModZ[PlayerNumber()] < 96.0)
                ModZ[PlayerNumber()] += 4.0;
         }

SetActorPosition(100+PlayerNumber(), x, LVL_YPOS+ModY[PlayerNumber()], z+32.0+ModZ[PlayerNumber()], 0);
Spawn("Shadow", 0, 0, 0, 900+PlayerNumber(), 0);
SetActorPosition(900+PlayerNumber(), x, LVL_YPOS, GetActorFloorZ(0), 0);
delay(1);
}
}

// Pogo!

Script 5 (VOID) { 
    If(Pogo[PlayerNumber()] == False && GetActorProperty(0, APROP_HEALTH) > 0)
        {   SetActorState(0, "Pogo"); Pogo[PlayerNumber()] = True; 		PogoFirst[PlayerNumber()] = True; Delay(8); 
                PogoFirst[PlayerNumber()] = False;	}

    else    if  (GetActorProperty(0, APROP_HEALTH) > 0)
                {   if(GetActorVelZ(0) < 0)
                    SetActorState(0, "JumpFall");
                    else SetActorState(0, "Spawn"); Pogo[PlayerNumber()] = False;    }}
    

// Player movement/aiming script

Script 6 (void)
    {
        int Button = GetPlayerInput(-1, INPUT_BUTTONS);
        
        if(Pogo[PlayerNumber()] == False)
            {
            
                        DownFirst[PlayerNumber()] = False; 
                        UpFirst[PlayerNumber()] = False;
                        DownBuffer[PlayerNumber()] = 0;
                        UpBuffer[PlayerNumber()] = 0;
                        
        if(GetActorZ(0) - GetActorFloorZ(0) == 0   &&
                    Button & BT_LOOKUP)
                        {
                            SetActorState(0, "ShootUp");
                            if(CheckInventory("NeuralAmmo") > 0)
                                {
                                    SetActorPosition(0, getactorx(0), LVL_YPOS, getactorz(0)+16.0, 0);
                                    SpawnProjectile(0, "NeuralStun", GetActorAngle(0), 0, 60, 0, 0);
                                    SetActorPosition(0, getactorx(0), LVL_YPOS, getactorz(0)-16.0 ,0);
                                    TakeInventory("NeuralAmmo", 1);
                                }
                            else
                                AmbientSound("stunner/empty", 127);
                                
                        }
    else if(GetActorZ(0) - GetActorFloorZ(0) != 0   &&
                    Button & BT_LOOKUP)
                        {
                            SetActorState(0, "ShootJumpUp");
                            if(CheckInventory("NeuralAmmo") > 0)
                                {
                                    SetActorPosition(0, getactorx(0), LVL_YPOS, getactorz(0)+16.0, 0);
                                    SpawnProjectile(0, "NeuralStun", GetActorAngle(0), 0, 60, 0, 0);
                                    SetActorPosition(0, getactorx(0), LVL_YPOS, getactorz(0)-16.0 ,0);
                                    TakeInventory("NeuralAmmo", 1);
                                }
                            else
                                {
                                    AmbientSound("stunner/empty", 127); 
                                    delay(20);
                                }
                        }
    else if(GetActorZ(0) - GetActorFloorZ(0) != 0   &&
                    Button & BT_LOOKDOWN)
                        {
                        SetActorState(0, "ShootJumpDown");
                            if(CheckInventory("NeuralAmmo") > 0)
                                {
                                    SetActorPosition(0, getactorx(0), LVL_YPOS, getactorz(0)+16.0, 0);
                                    SpawnProjectile(0, "NeuralStun", GetActorAngle(0), 0, -60, 0, 0);
                                    SetActorPosition(0, getactorx(0), LVL_YPOS, getactorz(0)-16.0 ,0);
                                    TakeInventory("NeuralAmmo", 1);
                                }
                            else
                                {
                                    AmbientSound("stunner/empty", 127); 
                                    delay(20);
                                }
                        }
    else  if(GetActorZ(0) - GetActorFloorZ(0) != 0)
                        {
                        SetActorState(0, "ShootJump");
                        if(CheckInventory("NeuralAmmo") > 0)
                                {
                                    SetActorPosition(0, getactorx(0), LVL_YPOS, getactorz(0)+16.0, 0);
                                    SpawnProjectile(0, "NeuralStun", GetActorAngle(0)>>8, 60, 0, 0, 0);
                                    SetActorPosition(0, getactorx(0), LVL_YPOS, getactorz(0)-16.0 ,0);
                                    TakeInventory("NeuralAmmo", 1);
                                }
                            else
                                {
                                    AmbientSound("stunner/empty", 127); 
                                    delay(20);
                                }
                        }
    else  
                        {
                        SetActorState(0, "Shoot");
                        if(CheckInventory("NeuralAmmo") > 0)
                                {
                                    SetActorPosition(0, getactorx(0), LVL_YPOS, getactorz(0)+16.0, 0);
                                    SpawnProjectile(0, "NeuralStun", GetActorAngle(0)>>8, 60, 0, 0, 0);
                                    SetActorPosition(0, getactorx(0), LVL_YPOS, getactorz(0)-16.0 ,0);
                                    TakeInventory("NeuralAmmo", 1);
                                }
                            else
                                {
                                    AmbientSound("stunner/empty", 127); 
                                    delay(20);
                                }
                        }
                        
             }           
    Pogo[PlayerNumber()] = False;
                        
}

// Run randomly by certain monsters - in lieu of using A_Chase they are using thrustthing methods.
Script 8 (VOID)
{
    if(Random(1, 2) == 1)
        SetActorAngle(0, 0.5);
    else
        SetActorAngle(0, 1.0);
}

Script 100 (VOID)
{
    int x = GetActorX(0);
    int z = GetActorZ(0);
    int vx = GetActorVelX(0);
    int vz = GetActorVelZ(0);
    Spawn("Daze", x, LVL_YPOS, Z+24.0, 1801, 0);
    SetActorPosition(1801, x, LVL_YPOS, z+24.0, 0);
        While(vx != 0 || vz != 0)
            {
                vx = GetActorVelX(0);
                vz = GetActorVelZ(0);
                x = GetActorX(0);
                z = GetActorZ(0);
                SetActorPosition(1801, x, LVL_YPOS, z+24.0, 0);
                Delay(1);
            }
}

// This allows the player to travel between tagged doorways - this works by the player's aim up key being
// also bound to the USE function.  Place a 'player uses sector' actor to run this script and define the
// mapspot to teleport to through the doorway

Script 99 (int MapSpot)
    {
        if(Pogo[PlayerNumber()] == False &&
            GetActorZ(0) - GetActorFloorZ(0) == 0 &&
                GetActorProperty(0, APROP_HEALTH) > 0)
            {
        SetPlayerProperty(0, ON, PROP_TOTALLYFROZEN);
        YSuspend[PlayerNumber()] = True;
        SetActorState(0, "Enter", 0);
        for(int Mloop = 35; Mloop > 0; MLoop--)
            {
                int x = GetActorX(0);
                int y = GetActorY(0);
                int z = GetActorZ(0);
                SetActorPosition(0, x, y+2.0, z, 0);
                delay(1);
            }
        SetActorPosition(0, GetActorX(MapSpot), GetActorY(MapSpot), GetActorZ(MapSpot), 0);
        SetActorState(0, "Exit", 0);
        While(GetActorY(0) > LVL_YPOS)
            {
                x = GetActorX(0);
                y = GetActorY(0);
                z = GetActorZ(0);
                SetActorPosition(0, x, y-2.0, z, 0);
                delay(1);
            }
        SetActorPosition(0, x, LVL_YPOS, z, 0);
        SetActorState(0, "Spawn");
        SetPlayerProperty(0, OFF, PROP_TOTALLYFROZEN);
        YSuspend[PlayerNumber()] = False;
        }
    }


// This is for ledge grabbing which I haven't implemented
Script 101 (VOID)
    {
        int TID;
        for(int Iterate = 100; Iterate > 0; Iterate--)
            if(ThingCount(T_NONE, Iterate+900) == 0)
                TID = Iterate+900;
                
        if(GetActorAngle(0) == 1.0)
        Spawn("WallCheck", GetActorX(0)+20.0, GetActorY(0), GetActorZ(0)+100.0, TID);
        else
        Spawn("WallCheck", GetActorX(0)-20.0, GetActorY(0), GetActorZ(0)+100.0, TID);
        
        if(GetActorFloorZ(TID) != GetActorFloorZ(0)) SetResultValue(1);
                else SetResultValue(0);
        Thing_Remove(TID);
    }

here are the resources/decorate
http://www.sendspace.com/file/s31osv

Llewellyn
Forum Regular
Posts: 578
Joined: Mon Jul 02, 2012 7:12 am

RE: Commander Keen TC

#13

Post by Llewellyn » Fri Jul 27, 2012 9:43 am

Thanks dude, I'll definitely save a bunch of time with this, and give you the credit for anything I use.

Also I hadn't thought about respawning the monsters/items like that, it's a really good idea.
Looking at your code I think I might switch from using the system I have right now to Getplayerinput, it certainly looks a lot cleaner.

Since I have my maps really funky, I'll have to modify the doorway code (I am gonna use part of yours because I only had the animation sequences done, and no actual teleporting) for linedefs.

PS. I would have suggested using a 2D array instead of all those arrays, I used one like this:
players[playernumber][action] and #Defined the numbers for each action.
Last edited by Llewellyn on Fri Jul 27, 2012 9:50 am, edited 1 time in total.

TheMisterCat
 
Posts: 79
Joined: Mon Jun 04, 2012 2:21 pm
Location: NZ

RE: Commander Keen TC

#14

Post by TheMisterCat » Fri Jul 27, 2012 9:49 am

funnily enough, I didn't actually have to code in the super pogo jump, it just works naturally with the way the pogo script works. i hear they stumbled upon it the same way with the original keen, and just left it in as a feature

Llewellyn
Forum Regular
Posts: 578
Joined: Mon Jul 02, 2012 7:12 am

RE: Commander Keen TC

#15

Post by Llewellyn » Fri Jul 27, 2012 10:53 am

TheMisterCat wrote: funnily enough, I didn't actually have to code in the super pogo jump, it just works naturally with the way the pogo script works. i hear they stumbled upon it the same way with the original keen, and just left it in as a feature
Oh, nice, I think I might have to steal your method then, because I totally couldn't get mine to do the Impossible Pogo Trick right.

Also it was called that then because keyboards weren't really responsive enough with the software and hardware to press the keys together at the right time....

EDIT: From what I understand...

Code: Select all

<Llewellyn> From what I understand, when you hit "Pogo" your sprite changes so you're off the ground, but then "Gravity" pulls you down so you hit the ground almoast immediately, but you can jump just before that first hit
<&TerminILL> huh. I never really thought about it, but that sounds pretty accurate. I'd give it about three or four frames at a very conservative guess
<Llewellyn> So an accurate representation would be to lift the player off the ground, then check to see if they hit jump before they touch?
<&TerminILL> That seems reasonable.
Last edited by Llewellyn on Fri Jul 27, 2012 11:27 am, edited 1 time in total.

TheMisterCat
 
Posts: 79
Joined: Mon Jun 04, 2012 2:21 pm
Location: NZ

RE: Commander Keen TC

#16

Post by TheMisterCat » Fri Jul 27, 2012 12:15 pm

well, mine will just add the velocity of the pogo thrust to the initial jump if the pogo+jump are pressed close enough to eachother, so it is a little higher than the original

Llewellyn
Forum Regular
Posts: 578
Joined: Mon Jul 02, 2012 7:12 am

RE: Commander Keen TC

#17

Post by Llewellyn » Sat Jul 28, 2012 12:09 am

TheMisterCat wrote: well, mine will just add the velocity of the pogo thrust to the initial jump if the pogo+jump are pressed close enough to eachother, so it is a little higher than the original
That's basically what happens, when you hit the ground for the first time in the original you get one little bit of "jump" added to the pogo height.

TheMisterCat
 
Posts: 79
Joined: Mon Jun 04, 2012 2:21 pm
Location: NZ

RE: Commander Keen TC

#18

Post by TheMisterCat » Sat Jul 28, 2012 3:59 am

let me know if you manage to properly implement ledge grabbing, I never got around to that

Llewellyn
Forum Regular
Posts: 578
Joined: Mon Jul 02, 2012 7:12 am

RE: Commander Keen TC

#19

Post by Llewellyn » Sat Jul 28, 2012 4:30 am

TheMisterCat wrote: let me know if you manage to properly implement ledge grabbing, I never got around to that
Actually that's already done :P

TheMisterCat
 
Posts: 79
Joined: Mon Jun 04, 2012 2:21 pm
Location: NZ

RE: Commander Keen TC

#20

Post by TheMisterCat » Sat Jul 28, 2012 4:44 am

care to show your work?

Post Reply