What will I need to learn to make this work?

Since I've got my summer vacation coming up in a few months, I figured I'd use the time off to work on a programming project. While I technically [italic]could[/italic] finish it with the knowledge I have now, the interface would be ridiculously cumbersome and it would be very tedious and inefficient.

Long story short, I have tutorials I can use to learn these things, but knowing how long this project will likely take, I'd like to save myself some time by learning only what I need to.

The project is actually a game - a sci-fi strategy RPG whose basic gameplay will be similar to Fire Emblem, Shining Force, Super Robot Wars, etc. I already have a trial version of the basic combat system worked out, so no worries there. Moving characters around the map and attacking, though, is what I can't do very well right now. Here's the breakdown:

-Characters are set up using records that hold their weapons, armor, map position, etc. How difficult would it be to make it so players can save these? Obviously, I want players to be able to pick up where they left off without losing any stats.

-Maps will be made using a two-dimensional array. Player characters will be denoted using numbers 1-9 (there's a limit of 8 on the field at any time, so it won't screw up the map) and NPCs will be denoted with the letters a-z. This lets me set up a fairly simple command system, with stuff like "Mov 5 2R 2U" to move unit 5 2 to the right and 2 up, or "3 Atk C W1" to have unit 3 attack enemy C with its main weapon, I'd prefer a more traditional system where the player moves a cursor around the map. Would this be difficult, or would I be better off with the command system.

-Finally, there's the matter of how attacking itself will work. Let's take the attack command I mentioned before as an example:

"3 Atk C W1"

Here's a brief breakdown of what I want to happen:

As part of its record, the player character will have something like "mapnumber : integer", which will be set to "pc3.mapnumber := 3". The "3", that the player puts will then be used to reference the pc3 record, which will then be used in the following battle procedure. Likewise for C representing what enemy will be used and W1 representing what weapon will be used. The only problem? I don't really know how to do this.

...That's basically a summary of the difficulties I'll have. I'll appreciate whatever help I can get, but again, I'm only looking for general advice on what I need to learn to make this work rather than specific advice on how to do these things. If I run into further trouble, I'll ask.

Thanks to anyone who can help with this.
«1

Comments

  • : I want players to be able to pick up where they left off without
    :losing any stats.

    Commercial games are built around a robust save/load system, they are basically script interpreters... To implement a save function all game data has to be captured ( characters, map, npc's, objects, control variables etc. ) to a file and the main game loop must facilitate putting all this data back upon "load". This can be done many ways, depending how the game is designed... I would use objects instead of arrays to represent characters, npc's etc., because one could profit from the advantages of using objects (inheritance, private data, easier debugging etc.)

    : ...stuff like "Mov 5 2R 2U" to move unit 5 2 to the right and 2 up,
    :or "3 Atk C W1" to have unit 3 attack enemy C with its main weapon,
    :I'd prefer a more traditional system where the player moves a cursor
    :around the map. Would this be difficult, or would I be better off with
    :the command system.

    I would go with the "point and click" controls, don't have to implement a parser for the command lines and is more user friendly.

    If you know C/C++ you could look at: stratagus.sourceforge.net/ (sources)
  • : -Characters are set up using records that hold their weapons, armor,
    : map position, etc. How difficult would it be to make it so players
    : can save these? Obviously, I want players to be able to pick up
    : where they left off without losing any stats.

    You can easily save your player data and if desired you could save game data as well. If your game is like Zelda, where you always start in the same location no matter where you save, then saving the player record is enough. If your player encounters other players that level up as well or change throughout the game, you will need to also save game data (NPC locations, levels, etc).
    Since it's your game, you can design the save file however you want. Anything from just throwing the player record in, followed by NPC data, etc or creating a sectioned save file allowing you to select different data to save at different times (more information when in a cave, etc)


    : -Maps will be made using a two-dimensional array. Player characters
    : will be denoted using numbers 1-9 (there's a limit of 8 on the field
    : at any time, so it won't screw up the map) and NPCs will be denoted
    : with the letters a-z. This lets me set up a fairly simple command
    : system, with stuff like "Mov 5 2R 2U" to move unit 5 2 to the right
    : and 2 up, or "3 Atk C W1" to have unit 3 attack enemy C with its
    : main weapon, I'd prefer a more traditional system where the player
    : moves a cursor around the map. Would this be difficult, or would I
    : be better off with the command system.

    Typing is very old school (althouh I love the classics). It's hard to tell though without seeing the game setup. It may not work well without typing commands, but if so, definately go with cursor controls (and/or joystick and/or mouse).


    : -Finally, there's the matter of how attacking itself will work.
    : Let's take the attack command I mentioned before as an example:
    :
    : "3 Atk C W1"
    :
    : Here's a brief breakdown of what I want to happen:
    :
    : As part of its record, the player character will have something
    : like "mapnumber : integer", which will be set to "pc3.mapnumber :=
    : 3". The "3", that the player puts will then be used to reference the
    : pc3 record, which will then be used in the following battle
    : procedure. Likewise for C representing what enemy will be used and
    : W1 representing what weapon will be used. The only problem? I don't
    : really know how to do this.

    Again, with cursor controls, you could have menu based fights or real-time battles. Weapons could be changed via menu or keys/buttons.

    Most of what you want won't be extremely hard to implement, but it will take some time ;)

    If you want more in depth help, we're here!
  • "You can easily save your player data and if desired you could save game data as well. If your game is like Zelda, where you always start in the same location no matter where you save, then saving the player record is enough. If your player encounters other players that level up as well or change throughout the game, you will need to also save game data (NPC locations, levels, etc).
    Since it's your game, you can design the save file however you want. Anything from just throwing the player record in, followed by NPC data, etc or creating a sectioned save file allowing you to select different data to save at different times (more information when in a cave, etc)"

    Hmmm...as stated before, this is gonna be a strategy RPG, so everything's broken up into different levels/maps. Whether or not I allow players to save mid-map is going to make a big difference in how I write my save files. The mid-battle save is more prone to abuse (your attack didn't do enough damage and the counter killed you? Reload!), but it means people will be able to play the game for smaller amounts of time. Thanks for giving me that to think about, though.

    "Typing is very old school (althouh I love the classics). It's hard to tell though without seeing the game setup. It may not work well without typing commands, but if so, definately go with cursor controls (and/or joystick and/or mouse)."

    As of now, the battle screen will look something like this:

    [code]
    @.
    @...b
    .|___...c.
    .2...|...d
    ..1..|....
    [/code]

    With the dots representing plains, the lines representing roads, etc. Because this would result in the game being text-based, I can imagine I would have difficulty making any sort of cursor system. How much more trouble would it be to switch to a graphical interface?

    In summary, I'd like to thank those who replied. I'm making a few balance touches to the battle system. Once that's done, I'll put it on Filefront for review. I would appreciate if anyone could look over it then I would greatly appreciate it. (Honestly, I could probably make a lot better use of functions than I am now)

    Brief summary of my main concerns:

    -Making everything efficient
    -Making a user interface that doesn't make people want to tear their hair out
    -As a side note (need to know this to check weapon ranges on the map grid), is there a quick-and-easy way to do absolute values in Pascal?

    I'll reply again when I run into further trouble.
  • :-As a side note (need to know this to check weapon ranges on the map grid), is there a quick-and-easy way to do absolute values in Pascal?

    The function: [b]abs[/b]
  • : Hmmm...as stated before, this is gonna be a strategy RPG, so
    : everything's broken up into different levels/maps. Whether or not I
    : allow players to save mid-map is going to make a big difference in
    : how I write my save files. The mid-battle save is more prone to
    : abuse (your attack didn't do enough damage and the counter killed
    : you? Reload!), but it means people will be able to play the game for
    : smaller amounts of time. Thanks for giving me that to think about,
    : though.

    If you want to allow this, you could have a quick save button (F3 save / F5 load) or if not, you can have save points or ability to save only when there are no enemies on screen / within a certain distance.

    : As of now, the battle screen will look something like this:
    :
    : [code]:
    @.
    @...b
    : .|___...c.
    : .2...|...d
    : ..1..|....
    : [/code]:
    :
    : With the dots representing plains, the lines representing roads,
    : etc. Because this would result in the game being text-based, I can
    : imagine I would have difficulty making any sort of cursor system.
    : How much more trouble would it be to switch to a graphical interface?

    Not at all. You would still have a Letter to represent your player right? You would just need to have one procedure draw your background and the next draw your player on top of the background. Your main procedure would look something like this:
    [code]
    Begin
    Setup;
    Repeat
    Draw_Background;
    Draw_Enemies;
    Draw_Player;
    Move_Enemies;
    Move_Player;
    Until QuitGame;
    End.
    [/code]

    Your player should always have some sort of X, Y value, so you would use your Move_Player procedure to change these and check for collisions with mountains, trees, etc.
    As for graphical, if you get it going in text first, then it's just a matter of changing letters for drawings. Not all that difficult.

    : In summary, I'd like to thank those who replied. I'm making a few
    : balance touches to the battle system. Once that's done, I'll put it
    : on Filefront for review. I would appreciate if anyone could look
    : over it then I would greatly appreciate it. (Honestly, I could
    : probably make a lot better use of functions than I am now)

    I would gladly look at it for you (may take a few days) and give suggestions for speedups, improvments, bug fixes, etc. Also, later I can give you a hand implementing graphics if desired.
  • Thanks again for the help. However, before I do anything else, I need to work this out...

    I just tried to make a program using pointers, very quick and minimalist. The idea is simple, and a reflection of the sort of thing I'll need to do in my main project. The program is supposed to read whether the user types in "A", "B", or "C", then display the corresponding number. This is supposed to work by pointing at the variable EQUAL to choice (I.E., if the user picks choice A, then the pointer points to variable A.) Here's what I came up with:

    [code]
    program Pointers;

    uses
    Crt;

    var
    p1: ^integer;
    A, B, C: integer;
    choice: char;

    begin

    ClrScr;
    A := 10;
    B := 300;
    C := 2500;
    writeln (' What kind of number do you want?');
    writeln (' A: Small');
    writeln (' B: Average');
    writeln (' C: Large');
    readln (choice);
    p1 := @(choice);
    writeln (p1^);
    readln;

    end.
    [/code]

    Long story short, it doesn't work. It tends to give me a number between 50 and 70, presumably the ID of the character I put in. I could do something like this:

    [code]
    if choice = A then
    p1 := @(A);
    if choice = B then
    p1 := @(B);
    if choice = C then
    p1 := @(C);
    [/code]

    But in my main project, I'll be dealing with a lot more variables than these, so I'll need to be more efficient than that.

    Sorry for asking what seem like basic questions, but to be honest I have no access to professional training. All of the tutorials I've found explain how to do the different functions, but don't really go into much detail or tie everything together.
  • Pascal doesn't let you access variables by variable names. So you can't say "I want a pointer to point to 'A' when the user types 'A'"

    However, there is a method that you can use that "will" work that way.
    Quick explanation:
    (1) Pascal assigns each variable to a location in the 'Data Segment'. (2) These variables are assigned in order from first to last.
    (3) We can (as in your example) get a pointer to a variable
    (4) These variables are WORD aligned! That means that a BYTE or CHAR actually takes up two bytes if followed by a variable that is NOT a BYTE or CHAR.

    So with that info, we can do this:

    [code]
    VAR
    Choice : Byte; { We only have one byte here, so there will be a BYTE space wasted }
    A, B, C : Integer; { It is IMPORTANT that these follow directly after Choice! }
    P1 : ^Integer;

    Begin
    ClrScr;
    A := 10;
    B := 300;
    C := 2500;
    writeln (' What kind of number do you want?');
    writeln (' A: Small');
    writeln (' B: Average');
    writeln (' C: Large');
    readln (choice);

    (*****************************************************************
    * The following lines looks like this:
    * p1 := @Choice + <-- Address of Choice
    * 2 + <-- 1 byte for Choice and 1 to align
    * (Ord(UpCase(Choice))-65) <-- A=65, so A-65=0, B-65=1, etc
    * * SizeOf(Integer) <-- Multiply by # of bytes each one uses
    *)

    { DSeg = Data Segment }
    p1 := Ptr(DSeg, Ofs(Choice) + 2 + (Ord(UpCase(Choice))-65)*SizeOf(Integer));
    writeln (p1^);
    readln;
    End.
    [/code]

    If you still don't understand, basically it finds the address of Choice, then adds 2 to move the address to the start of the A, B, C variables. Then it adds 2 bytes for every letter past 'A'.
    *NOTE* If you change the variable names to something other than A,B,C you will still have to type A,B,C,etc in to access them.

    This isn't a great way of coding, but if it has to be done, it can be.
    Usually there is a better method of going about this. I would suggest posting at least a section of your code as to what you are trying to do and we can help you find a better method.
  • Hmmm, all right. I'll post my combat demo soon. I just have to make some adjustments to get it more similar to how the actual game will work.

    EDIT: Okay, revisions are finished. I've put the code on Pastebin to prevent message from getting too long.

    [link=http://pastebin.com/m1f08ff86]Sample code[/link]
  • Your code is well documented & your records are nicely constructed, but your code is poorly laid out. You have no functions or procedures, all the code is in the main section. Don't be afraid to use to many procedures. If you think something seems like it should be it's own thing, make it one.

    I think I stated above, your main Begin...End section should look very small, possibly like so:
    [code]
    Begin
    Setup;
    [b]GetCharacter(pc1);[/b]
    Repeat
    Draw_Background;
    Draw_Enemies;
    Draw_Player;
    Move_Enemies;
    Move_Player;
    Until QuitGame;
    End.
    [/code]

    All your first lines of code should go into Setup (Player stats initialization, etc)
    The GetCharacter() procedure currently would be all your questions for setting up your character, but later could also add in a load option.

    Also, for setting up your character, the text can be a bit confusing. I would recommend using arrow keys for inputing stats, either a bar or a number that allows you to add or remove points.
    The screen could look like so:
    [code]
    Please distribute skill points: You have 185 points left.
    [b]
  • Thanks for taking the time a quick and helpful reply, Phat Nat. I learned from your suggested improvements, and I'll be sure to put them in place. It's nice to get useful help from actual people rather than just generic, sparse tutorials =)
  • Glad I could help.

    May I recommend using String[12] instead of 'packed array[1.12] of char', unless you have a specific reason for the other.
    Does XP reset itself? If not, you may want something larger than smallint.

    [code]
    fighter = record { These records store character stats }
    [b]callsign : string[12][/b]; {packed array [1..12] of char;}
    {...}
    lvl : smallint; { Character level. }
    [b]xp : smallint;[/b] { Character gains a level every 100 exp. Unused in demo.}
    end;
    [/code]

    [QUOTE]
    It may seem strange that I use so many reals where
    it looks like I could get by with integers, and
    save myself a lot of rounding and truncating in the
    process. The fact is, combat rolls rely heavily on
    divison. Integers tend to do this pretty poorly
    since they can't have decimals, so such a system
    could result in stuff like the player gaining 5 def
    and halving the damage they take, or gaining 200 def
    and getting no benefit.
    [/QUOTE]

    You [u]could[/u] use integers and just use Real variables to hold your results.
    INTEGER / INTEGER will result in a REAL.
    INTEGER div INTEGER will result in an INTEGER.
    ...but using all REALs work just as well ;)
  • I ran the code you gave me to see if everything checked out. At this line, though:

    Mem[color=Red][[/color]$B800[color=Red]:[/color] (YPos+1) * 160 + x*2 + 1] := $1F;

    It gave me the following errors:

    [code]Error: Identifier not found "Mem"
    Fatal: Syntax error, "]" expected but ":" found[/code]

    I have highlighted the points of the code it listed for those errors in red.

    I'm afraid I can't figure out the problem myself, as most of what you've shown is still pretty new to me.
  • The arrays [b]mem[/b] and [b]memw[/b] were removed from FP ( they only exist on the go32v2 platform mapping the DOS memory ). Either use TP or the CRT unit routines.
    [b]mem[$b800:...[/b] writes directly into the video memory thus being very fast since the hardware does the job at every screen refresh not a much slower software routine. The main advantage is that leaves the cursor where is, basically the cursor can be hidden ( by moving it outside the visible area ) while display takes place, resulting in less flicker and nicer visual effect. It is possible to mimic this with FP and Windows by using Win API's, however coding it is a bit more difficult. If you interested, may find this site useful: http://www.paradicesoftware.com/lx5suite/page_lx5suite.htm
  • Soory, I haven't worked eith Free Pascal, still old school Turbo Pascal ;)

    Another option is to just rewrite the information each time. Since speed doesn't matter much for something as simple as this, it's no problem.

    Try this instead (runs as is, just implement it into your program & modify as you want):
    [code]
    USES Crt, Dos;

    FUNCTION Pad ( S: String; C : Char; L : Byte) : String;
    Begin
    While Length(S) < L Do S := S + C;
    Pad := S;
    End;

    CONST
    totalSkillPts = 103;
    skillNames : Array[0..4] Of String =
    ('Defense','Evasion','short-range weapons','mid-range weapons','long-range weapons');
    kEnter = #13;
    kUp = #72;
    kDown = #80;
    kLeft = #75;
    kRight = #77;
    VAR
    Key : Char;
    x : Byte;
    YPos : Byte;
    Count : Byte;
    tempSkills : Array[0..4] Of Integer;
    skillPts : Integer;

    Begin
    { tempSkills[0] := pc1.defskill;
    tempSkills[1] := pc1.evaskill;
    tempSkills[2] := pc1.shortskill;
    tempSkills[3] := pc1.midskill;
    tempSkills[4] := pc1.longskill;}
    ClrScr;

    { This never changes, so just write it once where we want it }
    gotoXY(1,10);
    WriteLn(' Press ''E'' to equalize all points');
    gotoXY(1,12);
    WriteLn(' Use arrows keys to modify:');
    WriteLn(' Up/Down to select skill');
    WriteLn(' left/right to subtract/add points.');
    WriteLn;
    WriteLn(' Press ENTER when finished');

    skillPts := totalSkillPts;
    YPos := 0;
    Repeat
    GotoXY(1,1);
    Write('Please distribute skill points: You have ');
    TextColor(15); Write(skillpts:3);
    TextColor( 7); WriteLn(' points left. ');
    For Count := 0 to 4 Do
    Begin
    { Set background color to White on Blue if currently selected }
    If YPos = Count Then
    Begin TextBackground(1); TextColor(15); End
    ELSE
    Begin TextBackground(0); TextColor(7); End;
    GotoXY(2,3+Count);
    Write(' '+Pad(skillNames[Count],' ',22), '[', tempSkills[Count]:3, '] ');
    End;
    { This is here to make sure that we don't have following
    screens or the top skill line written on a blue background }
    TextBackground(0); TextColor(7);

    Key := UpCase(Readkey);

    If Key = 'E' Then
    Begin
    SkillPts := totalSkillPts;
    { Add equal points to all }
    For Count := 0 to 4 Do
    Begin
    tempSkills[Count] := totalSkillPts DIV 5;
    SkillPts := SkillPts - tempSkills[Count];
    End;
    { If we have extra/too many points, add/subtract them
    I don't think it's possible with this setup to return a
    negative point value, but just in case, let's handle it.
    1/1 = 1, -1/1 = -1. This way we know to + or - points }
    For Count := 0 to ABS(SkillPts)-1 Do
    tempSkills[Count] := tempSkills[Count] + SkillPts DIV ABS(SkillPts);
    SkillPts := 0;

    End;
    If Key = #0 Then { Extended System Key pressed }
    Begin
    Key := Readkey;
    Case Key of
    kUp : If YPos > 0 Then Dec(YPos);
    kDown : If YPos < 4 Then Inc(YPos);
    kLeft : If tempSkills[YPos] > 0 Then
    Begin
    Dec(tempSkills[YPos]);
    Inc(SkillPts);
    End;
    kRight : If skillPts > 0 Then
    Begin
    Inc(tempSkills[YPos]);
    Dec(SkillPts);
    End;
    End;
    End;
    Until Key = kEnter;
    { pc1.defskill := tempSkills[0];
    pc1.evaskill := tempSkills[1];
    pc1.shortskill := tempSkills[2];
    pc1.midskill := tempSkills[3];
    pc1.longskill := tempSkills[4];}
    End.
    [/code]
  • Sorry for taking so long to reply, I've been busy with other things.

    This code has helped a lot, and it's put me well on my way to understanding how to do what I need to know. I can easily adapt this code when I add places to purchase equipment, too.

    As a side note, I ran my first test making a cursor system for the map screens, which failed. The code I tried was:

    [code]
    program cursortest;

    uses
    crt,
    dos;

    var
    key : char;
    quit : boolean;
    x : byte;
    y: byte;

    begin
    quit := true;
    while quit = false do
    begin
    case key of
    'd': Inc(X);
    'a': Dec(X);
    'w': Dec(Y);
    's': Inc(Y);
    'q': quit := true;
    gotoXY(X,Y);
    end;
    end.
    [/code]

    According to the error messages I got, I needed to use constants rather than variables. While I could do it like this:

    [code]
    If X = 1 then
    begin
    if y = 1 then
    gotoXY(1,1);
    if y = 2 then
    gotoXY(1,2);
    ...[/code]

    But, for obvious reasons, I'd rather not do it this way.

    ...So as not to fall into the trap of asking basic questions over and over, is there a good tutorial I could find this in? I've googled it, but haven't had much success in finding advanced information.
Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Categories