Game Development Community

New feature wish list.

by Michael Flynn · in Torque 3D Professional · 01/05/2012 (2:16 pm) · 33 replies

Hi all,

(First if this is in the wrong place I am Sorry!)

I have a feature(s) I'd love to see implemented in T3D.
I would love to have a menu item, or a trigger feature
that would do a game save for a player, and let you load
the next level of your game and keeps track of items the player has/ picks up
or buttons pushed on another level.
also, if you load the game up and continue where you last saved, all the stuff
killed or picked up, switches etc, remain the same as when you saved it.

I'd like a multi-level game that you travel between levels to activate/ pickup
items.

Kind of like Elder Scroll or Myst, games of that sort.
I'v searched for info on it and it seems to be something lots of users want too.


What extras does every one else want?

Thank for comments or suggestion it all helps!

Mike
Page«First 1 2 Next»
#21
01/08/2012 (7:18 am)
I'm not sure. I think it would be good to set it up so that you can simply exec() the save file to load the states. So the function would have to generate the script to recreate the objects and then mount them to the correct object and write it into the save.

Additionally, in the interest of completeness, if we want dso's compiled (say in our distributed build) we should also precompile the savegame before dumping it to disk. I don't know if the current iteration does this based on the flag or not.
#22
01/08/2012 (10:26 am)
Hey,

What if we just do a Memory DUMP at save time then, after we load the level, we Read in the saved Memory Dump file to restore the state of the game??

Would be the easiest way to get everything's state to a file, and added extra, you don't have to set save flags for items.

The system already has to track everything in memory for all the level.
We just need to dump that info...

Just a thought.
#23
01/08/2012 (11:09 am)
@Frank,

Naaaa, I get mad sometimes, I'v spent a lot of time and money on Torque and I love it, but I get frustrated at times, scripting isn't always easy.

Real I need to learn how to do scripting before this stuff I guess, but it would be nice feature to have.

Eventually, I want to make a game where you travel to different levels.

O well...

#24
01/08/2012 (11:21 am)
The more you work with torque the more you realise what comes with it, or how little you need to do to get it to work.

As far as travelling to different levels, depending on your game design new levels will be imperative, things like underground areas, caves and dungeons are best done as a different level still, large interiors or dynamic interiors. Take skyrim, well most RPGs for that matter every building is a new level.
#25
01/08/2012 (11:24 am)
@Michael,
It looks like Richard is going to make that a reality for you. Right now, there are some technical issues with mounts, but if you are not using mounts currently then it should work with some thought as to object creation order. I know it will require script, but anything you do with the engine eventually requires script and C++ changes. Ideally you could team up with a coder if time is an issue. If not then give Richard some time and be willing to learn enough to test the changes and you should have your save function.

For multiple levels you can load a mission after you save. Loading a mission is not magic, it is just calling the right script to launch it. The code to launch the main missions is in the GUI buttons. I promise that once you get your head around running a few scripts you will be off to the races! Maybe to help soften the blow go pick up Torsion as it has script hightlighting I believe. I don't know as I don't have it, but I have also been coding so many different languages for so long that they all look the same to me anymore.

@Richard,
That was kind of what I was thinking. Good point on the precompiling and saving as a DSO. Without that someone could hack something into the script file a little too easily. Is there a mechanism for that already? I would love to be able to do that explicitly from a console function. Thanks for looking into this.

This whole discussion is really firing up my brain. Now I am going to have to get my rear in gear to finish what I am working on so I can play with level generation again!
#26
01/09/2012 (4:18 pm)
I saved a player out using LocalClientConnection.player.save() and here's what it gave me:

//--- OBJECT WRITE BEGIN ---
new Player() {
   skin = "DarkBlue";
   isAIControlled = "0";
   dataBlock = "DefaultPlayerData";
   position = "-2.28149 -1.27846 0.0202708";
   rotation = "1 0 0 0";
   scale = "1 1 1";
   canSave = "1";
   canSaveDynamicFields = "1";
      client = "7750";
      cycleWeapon0 = "Ryder";
      cycleWeapon1 = "Lurker";
      cycleWeapon2 = "LurkerGrenadeLauncher";
      cycleWeapon3 = "ProxMine";
      cycleWeapon4 = "DeployableTurret";
      invDeployableTurret = "5";
      invLurker = "1";
      invLurkerAmmo = "30";
      invLurkerClip = "20";
      invLurkerGrenadeAmmo = "20";
      invLurkerGrenadeLauncher = "1";
      invProxMine = "5";
      invRyder = "1";
      invRyderAmmo = "8";
      invRyderClip = "10";
      mountVehicle = "1";
      totalCycledWeapons = "5";
};
//--- OBJECT WRITE END ---

So, it's saving the clientID, which is not useful. Probably have to ignore that, or fix it somehow.

I was thinking that if we could cycle through the mounted objects we could create and mount them on the spot (think generating script in the save function to add the new MyMountedObject(){} there, then mount it).

As far as the dso generation, there's a build option for it. You remove #define TORQUE_NO_DSO_GENERATION from the defines in torqueConfig.h. Now, making an option for the ::save() method would be a little elbow grease but probably not too hard.

@Michael - I have the mission cycling by triggers article in to QA, so as soon as they get time to make sure my stuff works as advertised it'll go into the official docs. The save game stuff will take a little longer.... lol!

A basic description of what I did is this: I create two global variables, $Server::TargetMission and $Server::TargetSpawn. Then, on the trigger I set two dynamic fields named mission and target. In the trigger's onEnterTrigger() callback I set the $Server::TargetMission to the name of the mission I want to open and $Server::TargetSpawn to the name of the spawn point I want to spawn at. Then I changed onCyclePauseEnd() in scripts/server/game.cs to this:

function onCyclePauseEnd()
{
   $Game::Cycling = false;
/*
   // Just cycle through the missions for now.

   %search = $Server::MissionFileSpec;
   %oldMissionFile = makeRelativePath( $Server::MissionFile );
      
   for( %file = findFirstFile( %search ); %file !$= ""; %file = findNextFile( %search ) )
   {
      if( %file $= %oldMissionFile )
      {
         // Get the next one, back to the first if there is no next.
         %file = findNextFile( %search );
         if( %file $= "" )
            %file = findFirstFile(%search);
         break;
      }
   }

   if( %file $= "" )
      %file = findFirstFile( %search );*/

   loadMission($Server::TargetMission);
}

Next I changed pickPlayerSpawnPoint() in core/scripts/server/spawn.cs to this:

function pickPlayerSpawnPoint(%spawnGroups)
{
   // Walk through the groups until we find a valid object
   for (%i = 0; %i < getWordCount(%spawnGroups); %i++)
   {
      %group = getWord(%spawnGroups, %i);

      if (isObject(%group))
      {
         %count = %group.getCount();
         for(%j = 0; %j < %count; %j++)
         {
            %spawnPoint = %group.getObject(%j);
            if(%spawnPoint.getName() $= $Server::TargetSpawn)
            {
               if(isObject(%spawnPoint))
               {
                  return %spawnPoint;
               }
            }
         }
      }
   }

   // Didn't find a spawn point by looking for the groups
   // so let's return the "default" SpawnSphere
   // First create it if it doesn't already exist
   if (!isObject(DefaultPlayerSpawnSphere))
   {
      %spawn = new SpawnSphere(DefaultPlayerSpawnSphere)
      {
         dataBlock      = "SpawnSphereMarker";
         spawnClass     = $Game::DefaultPlayerClass;
         spawnDatablock = $Game::DefaultPlayerDataBlock;
      };

      // Add it to the MissionCleanup group so that it
      // doesn't get saved to the Mission (and gets cleaned
      // up of course)
      MissionCleanup.add(%spawn);
   }

   return DefaultPlayerSpawnSphere;
}

In the editor, you then open the datablock editor, create a new TriggerData called transitionTrigger. Set up the onEnterTrigger() callback like this:

function transitionTrigger::onEnterTrigger(%this, %trigger, %obj)
{
   echo(" -- entered " @ %trigger.getName());
   // get the .mission dynamic field value of the activated trigger 
   // and assign it to the global variable $targetPoint for use when 
   // loading the next mission file
   
   $Server::TargetMission = %trigger.mission;
   $Server::TargetSpawn = %trigger.target;
   
   cycleGame();
}

Remember to set the dynamic fields on the trigger, and you need to set up a spawnpoint in the target mission with the right name. Also, you need to ensure that you place your spawnspheres in the PlayerSpawnPoints SimGroup or you will drop into the new mission at the default spawn point.

Ok, a little more than a quick explanation. The article is nicer and it has pictures....

EDIT: Pretend you don't see my debugging echo()'s....
#27
01/11/2012 (7:21 pm)
Been away, playing with web site design..
This is great, I was talking to my friend and he was saying that in Python you can dump memory variables out to a file wit one command! If you had a screen with a bunch of controls you could set them as you wanted and then dump the whole thing to a file instead of writing a bunch of file writing code.

As I said, I think the best way would be to freeze the game, dump all the memory areas for the game to a file. then to load it up, just load the level, let it populate as normal, then load in the saved memory file and resume the game at that point.

I just remember this way of saving from some old games in the "day".

I Appreciate Richards efforts so don't think I am ignoring him, he's doing a great job, I'm just throwing out ideas.

Thank Richard!

Mike
#28
01/11/2012 (8:33 pm)
The difference is hundreds of megabytes or thousands of bytes. The first is wasteful. There is already code in the engine to do the object saving, which is what the Sim is, SimObjects running in a Sim. So saving their states is the same and more efficient and faster. Your users would not appreciate filling their hard drive with save game files that are 100MBs a piece.
#29
01/12/2012 (8:39 am)
You only need to save the variables area of memory, not the entire program.
This would be small, I guess we are talking about the same thing really, just saving the states of all the objects in a mission.

I Appreciate Richards and Everyone's efforts and time!!!
#30
01/12/2012 (8:46 am)
If you're saving global variables, have a look at the export function used to save prefs to a file:
export("$Pref::*", "./prefs.cs", False);
Or, for a better solution, Steve recently posted a resource to save out an ArrayObject into a file. If you have one global ArrayObject to save variables like inventory, you're nearly set.

RE saving mounted objects, I discovered that syntax like this is actually perfectly valid:
new AIPlayer(Bob) {
   datablock = DefaultPlayerData;
   new AIPlayer(Bill) {
      datablock = DefaultPlayerData;
   };
};
Both Bob and Bill are created, but for some reason Bill isn't added to any SimGroup. Unless I've botched something in the engine. On the one hand, it makes sense, because the engine can't count Bob as a SimGroup to add Bill to. On the other hand, the code should fall back to adding Bill to the RootGroup. Not sure why that fails.

Anyway, long story short, all it would take is a little additional code around the OP_ADD_OBJECT clause in compiledEval.cpp to fully support this syntax. Then a change to SceneObject::write to write out mounted objects using this syntax, and away you go. Much simpler than what I was trying to do before.

Then, of course, it'd be nice to change the editor to allow mounting objects without using the console. Which might actually be the most difficult change :P.
#31
01/12/2012 (6:41 pm)
Would this work?
new AIPlayer(Bob) {
   datablock = DefaultPlayerData;
   mountObjs = new SimGroup(){
      new AIPlayer(Bill) {
         datablock = DefaultPlayerData;
      };
   };
};
Then it could iterate over the objects in the SimGroup to mount the objects.
#32
01/13/2012 (5:16 am)
Ooh, that's sneaky. You'd still need to modify the write() method to save mission files with that syntax, though.
#33
01/13/2012 (6:52 pm)
And change that to check if your BobMountedStuff SimGroup exists before creating it, just in case.... You were going to name that, right? For ease of access at runtime? ;p
Page«First 1 2 Next»