Sunday, April 1, 2018

RPG: Terrain & Canopies

Lots of work has been completed on the RPG recently, so I'm trying to catch up on development posts now.

The game had all the terrain types hard coded. To get any kind of new terrain to show required creating the textures, adding new variables, calling functions to load those variables, and adding in switch cases to know where to load those textures. Took way too long.

The new method has a single text file that points to all the terrain types available.


The game loading function goes through each line of that file to parse the corresponding dat file for a specific terrain type.


Oceans happen to have 4 animated frames to give the illusion of waves. There are additional sprites for the ocean depending on how it borders neighboring textures (corners and sides). Those additional sprites are drawn when necessary to avoid hard edges for terrain such as water or grass.

The second line of the Ocean.dat has "o" - which is the code for this terrain type. The game's TerrainMap file is a 360x180 matrix of code letters that determine how the world looks.


There are so many unique variables a single block of terrain needs, I will inevitable go to a binary format. But for now just a large ASCII map is convenient.

In addition to the externalized terrain types, I've added a new concept called "canopies". Canopies are overlaid above the terrain to mimic things such as building roofs, but they don't block character movement.


Loading of canopies is handled very similar to terrain. There is a list of the canopy types.


And folders of each canopy type that contain a dat file and texture.


And finally the canopy map.


So although not much to look at now, these major changes allow me to greatly accelerate development.

The next post will be a significant one though! I've got a control scheme pretty well worked out and am in the process of implementing skills / spells.

Sunday, March 4, 2018

RPG: Initial AI & Multiple Levels

Two of my recent goals were to redo the memory management and implement an initial artificial intelligence.

Memory restructuring is complete - now using C++'s shared/weak_ptrs. I still have a few "new"s in there, but for anything that is created and destroyed during playtime those have all been swapped out. It will be significantly easier to split the game logic into multiple threads and support network play now.

(Initial) Artificial Intelligence


I also have finished an initial AI for the non-player characters. It's still VERY simple, but basically every character has a self allegiance. Trees are "cultural", squirrels are "wildlife", human civilians are "human civilians", and my current bad guys are "demons". Then each character has an allegiance rating to each allegiance type.

For example, the player could be neutral with "wildlife", friendly to "human civilians", and evil to "demons". Squirrels would keep their distance, civilians would walk up and talk, and demons would attack.

This unarmed civilian is walking up to talk to me...


But this armed guy is tagged as a demon and is attacking me...


Alternatively, the player could be friendly with "wildlife", evil to "human civilians", and friendly to "demons". Squirrels would approach, civilians would flee, and demons would say hi.

I'm still working on how the allegiance is dynamically changed. Ideas include feeding wildlife would increase your stance with them. Killing civilians would obviously make them hate you. And then to get on a demons good side? Sacrifices maybe?

Multiple Levels


In addition to the "whole world" 360 degree longitudes by 180 degree latitudes, I want the player to be able to go to additional level depths - such as underground cave systems or floors of buildings. I can now tag terrain tiles as pathways to go further down or up in depth.

This unbelievable crude buildings has a door on the south side.


Walking into that door transports the player to the same latitude & longitude, but to a different depth.


There is a tile to the south so the player may leave the building.

The inside terrain tiles are treated identically to the outside. Characters can be added, equipment can be dropped, etc. And you can still zoom out to see the whole world (at that map level).


I have a rudimentary edit mode in the game that lets me add characters to the map and save those to file. But my current map editor is making changes to what looks like bad ASCII art in Notepad, and it's holding me back. An in-game map editor may be in the next major update (multiple textures on characters is on hold for now).

Monday, February 26, 2018

RPG: Inventory

For my inventory system, I want to mimic the systems typically found in action RPGs, but they do have flaws I want to address.

Backpack


Although there is some fun playing the Tetris minigame in Diablo 1 and 2, it does pull from the core mechanic of the game. So I'm going with a backpack where you can hold up to 10 items regardless of shape. (I might make it so you can page through and hold 20 or 30 items, we'll see how important inventory becomes...)


The downside is you can hold 10 broadswords or 10 rings, but either way you'll be maxed out of space. That will probably be ok. If the balance doesn't work well, I could implement an idea of encumbrance and/or weight to solve the issue. That way you'd be limited to maybe 3 broadswords before being over encumbered whereas 10 rings would no problem. I'll see how the game develops before implementing that.

Money


For money, I'm having a separate purse that the player carries. Any money picked up will just go into that purse and not take up backpack slots. I'll set a maximum that can be held at a single time (to be determined as the game play gets worked out).


When someone carrying coins dies, a purse is left on the ground that can be picked up. Clicking the purse will transfer those coins into your own.


Potions


I think I've got a solid solution for Health and Mana potions. Diablo had the issue where you could put them on your belt, but they inevitably overwhelmed into your inventory. Thus taking the player back to Tetris and away from core gameplay.

But why are potions so freaking diluted with water? Concentrate that stuff, have a single potion bottle, and just take swigs of it when you need to!


In this screenshot the player has 7 drinks of health potion left and 3 drinks of mana potion left. 10 maximum for each.

And I've never been a fan of variable sized potions. Diablo/similar games had it balanced so that when your maximum hit points went up enough to take advantage of the bigger bottles also coincided when those bigger bottles became available also coincided with when you got enough money to afford them. So... what was the point? You'd always just get the best ones available.

If you take a swig of a health potion in my game, you get full health regardless of your maximum hit points. Sure I could make it so your maximum health went up and you could "buy" a bigger potion bottle, but it would be the same issue as in Diablo. By the time max hp goes up and bigger bottles become available your money is already up, so it's all an unnecessary wash.

And concerning health rejuvenating on its own - although it's convenient, it kills tension and disrupts gameplay (just flee for a bit, wait, then run back with full health). So I have zero plans on making health go up on its own. I don't think I can have mana go up on its own either as it will inevitable have the same issues as health. If you're trapped in a cave with low health and no supplies, I want you to keep that tension until you're actually out of the cave.

Weapons


I loved Diablo 2's concept of swappable weapons. Have the bow at long range then a quick key press and you're ready for melee combat. Awesome. Diablo 3 ruined it... I played as a wizard and it didn't matter if I was holding a sword or a wand, it was shooting magic bolts. (Seriously I don't know how the designers degraded the game that severely.) So what weapons you're holding will matter in my game, and I'll present good reasons to equip a variety.


All Together


And the current version of the inventory panel....



Friday, January 26, 2018

RPG: Tile Edges & Mouse

A lot has been improved since the last post on the RPG!


For one, I was introduced to the program Aseprite which has helped immensely with the art. My terrain tiles still aren't good, but at least they're not embarrassing!

And I've made four big code changes:

1. Tiles (such as ocean or grass) will now draw edge overlays onto neighboring tiles to smooth out the transitions. The overlays are also animated so the waves of water coming on and off the beach have movement.


2. You can perform basic melee attacks.


Here I've chopped down a tree and killed the guy on the beach.

3. Finished all movement via the mouse. Movement now mimics Diablo - click somewhere to go there, click on a guy to walk to him and attack, or click on an item to walk over and pick it up. If you're holding an item and you click on the map, drop the item in that direction. Keyboard movement is still supported and I still plan on adding joystick support, but the mouse movement is very nice.


No that isn't a giant sword on the ground, it's what I'm currently holding in my hand (tracks with the mouse cursor). If I click on the ground I'll place it down (and the sword sprite will scale down in size) or I can click it into my inventory window to wield it or put it in my backpack.

4. Some internal code changes with how I'm handling user inputs and executing those actions. Those changes enabled a single click to perform compound actions such as walk up to item/character and pick up/kill it.

Goals for next major update:


1. The memory management is currently not thread safe, so trying to scale up the number of items by making it multi-threaded is not feasible. I'm reworking my memory management now to support that.

2. A character's head, body, arms, legs, and feet are all in one sprite, but I really want the player's image to reflect the loaded equipment. If a sword is in the player's left hand, it should show in the left hand of the player. If the player is wearing red boots, then it should show red boots. If the player is holding 2 shields, then it should show holding 2 shields. Trying to use one sprite for all the possible equipment combinations is not feasible, so I'm going to experiment with drawing legs/feet separate from body separate from arms/hands separate from the head.

3. Implement a simple AI so characters will attack back.

Monday, December 18, 2017

Raspberry Pi Server: SVN Upgrade

My original plan was to upgrade my Raspberry Pi server to a new Pi 3, and use the original Pi 1 B+ for the Retro Pie. I've since backtracked for various reasons and put the Retro Pie SD card into the new Pi 3. So now my original server is back on the Pi 1 B+. The server had been working great except it was running out of disk space (only had a 4 GB SD Card).

Fairly simple to solve, I'll just use an external USB drive for storage! I plugged in a 32 GB USB drive, and now I needed to move my repository.

First I needed a folder to act as my reference location when I wanted to access the USB drive. It doesn't matter too much where, I went with: /media/usb

Created the folder with: sudo mkdir /media/usb
Set the ownership of the folder with: sudo chown pi /media/usb
Set the permissions of the folder with: sudo chmod 0777 /media/usb


After plugging in the USB device, I needed to know the device UUID by typing: sudo blkid


Then I needed to edit /etc/fstab for it to automount on boot: sudo nano /etc/fstab


For my new mount, I went with:
UUID=390A1652      /media/usb      vfat    uid=pi,gid=pi,umask=0000,sync,auto,nosuid,rw,nouser,nofail 0 0


As an alternative, I could specify to automount any USB drive that is plugged in as /dev/sda1. That seemed risky to me though as my current drive could change and the new drive could connect as /dev/sda1. That new drive wouldn't necessarily be vfat.

If I had wanted to mount any USB drive, the line would have read:
/dev/sda1        /media/usb      vfat    uid=pi,gid=pi,umask=0000,sync,auto,nosuid,rw,nouser,nofail 0 0

Lots of options and opinions on this:
uid & gid are my username; some references suggest entering the numeric value. You can check your account's id by typing: id -u and id -g. Turned out my pi user was 1000.
umask=0000 is the equivalent of chmod 0777 (everyone has read/write access).
sync has input and output be synchronously.
auto instructs the drive to mount automatically at bootup.
nosuid I don't understand, but one reference says: Block the operation of suid, and sgid bits.
rw to mount the drive with read-write access.
nouser permits only root to mount the filesystem.
nofail causes startup to not wait 90 seconds / error out if it fails to find the drive.

And finally reboot the Pi via: sudo reboot

The next task was to move my existing SVN repository to the external drive...

I stopped Apache which is used for SVN: sudo /etc/init.d/apache2 stop


I copied the repository over: cp -r repos /media/usb


Then I modified the Apache configuration to point to the new location of the SVN repository. The config file is located in /etc/apache2/mods-available, file dav_svn.conf: sudo nano /etc/apache2/mods-available/dav_svn.conf


My SVNParentPath was /home/pi/repos, I changed it to /media/usb/repos


Apache actually needs ownership of the repository folder, so I changed ownership to www-data: sudo chown -R www-data:www-data /media/usb/repos


And finally, restart Apache: sudo /etc/init.d/apache2 restart


I did a full restart to make sure everything came back up, and it did! So my SVN repository now has 32 GB to play with; far better than the few hundred MB from before.


The above instructions were mostly just for my reference in case I need to do this or similar again in the future, but I hope it can be of help to others!


Monday, December 11, 2017

Retro Pie

I've been playing some classic games on my laptop with emulators, but it's just not the same as on the T.V.. I had some time over the Thanksgiving holiday to do something about it. I've read many other sites using Retro Pie and decided to go with that.

I'm reusing my original Pi B+, but its existing 4 GB SD Card was inadequate for the task. So I picked up a new 16 GB card...



Downloaded Retro Pie off the website... Their instructions were fantastic: https://retropie.org.uk/docs/First-Installation/




Then got Win32 Disk Imager...


And used it to write the image to my SD card...


On the left is my existing Pi in its case, and on the right is the "Super Tinytendo" case I bought off Amazon for $20. The build quality on the Tinytendo is great. (From the reviews, it sounds like their first versions with rough 3-D prints. The one I bought however was injection modeled and of very high quality.) 


4 screws underneath to open the case...


And the Pi fits perfectly inside...


The power light in front is functional; the instructions were very simple and spelled out in the Tinytendo manual. The Power and Reset buttons are unfortunately not functional. It'd be interesting to make them so though.


I ended up overclocking my Pi B+ so it could handle SNES games better (more on that below). So out of precaution I added a heat sync from Adafruit over the CPU.


First boot!


RetroPie only shows emulators for the corresponding games it finds. So at first boot no emulators are shown; you have to load them up. ROMs can be added via USB, SFTP, or Samba share. Since I'm primarily a Windows user (uhg), I went the Samba route. The Samba Share was super easy to access and copy ROMs to. Just type \\retropie in file explorer and you're there!


After a reboot the appropriate emulators showed up!


Some of the SNES games were running a bit slow, so I decided to try overclocking. You can access the Raspberry Pi config options through the Retro Pie menu.


Selected the overclock option...


And set the overclock to Medium. The games are working reasonably well at this level so I'm hoping this will suffice.


I'm using two Logitech Gamepads for the controllers. They have a good layout for both NES and SNES systems (among others), but they also have a few additional buttons not used by those earlier consoles. I'm using the rear-most left button as my hotkey button. If I push hotkey + rear left then it loads my last save state; hotkey + rear right saves my current state, and hotkey + start quits the current game.


The Pi rounds up a nice collection for entertainment - Switch (newest) on the left, N64 (the best) in the middle, and NES/SNES (the classic) on the right.