Click here to Skip to main content

Those Magnificent Men, a game for Windows

Those Magnificent Men

Those Magnificent Men, previously called "The Catalyst" and "Island Hopper" is a 2D RPG based around aircraft. You play as young pilot designing your own airframe and running errands between towns and cities across the islands trading, buying/selling stock, hiring crew and dogfighting. 

The game is written in AGK (App Game Kit) which is a multi-platform language. It has two tiers of implementation, a high level, BASIC-style language (Tier 1), and a higher level, native language (Tier 2). Both tiers enable the developer to export the compiled code to a number of platforms such as Windows, iOS, Android, Blackberry, etc. See the AGK website here for more information on specifics of the development environment itself.

AGK was selected for Those Magnificent Men, for many reasons including, my familiarity with the code, the potential ability to export the completed game to other platforms and also because accessing the dedicated UltrabookTM stimuli, such as the GPS, accelerometers and touch-screen, was very easy. 

Plot and Setting 

Set in the 1920s over a small collection of islands where aircraft are the only logical choice of transport, four races of men (vampires, werewolves, merman and shadow people) are vying for political control. 

The Earth was once populated by a wide variety of men; Vampires, Werewolves, Mermen, etc. but the vast number of Humans have forced them to occupy a small group of Islands in the Pacific ocean, known as Tresto. The Islands are the last safe-place on Earth for all these mythical men, but the limited space and resources have caused these Mythical people distrust each other and they co-exist in a state of pending-war.

The player is one of the small number of humans on these islands, although the other races can be unlocked with progress.

You pilot between towns and cities doing jobs and trading stock while avoiding dog fights with pirates and enemy factions.

Features

Islands generated randomly (seeded by alpha-numeric string entered manually, or taken from GPS location) or drawn manually by the player (manual drawing is not in the current Demo).
Open-World exploration.
1000 individually named locations (all place names created by a human!).
Buy stock at one town and sell for a profit at another location across the islands.
Take on jobs for groups and political parties (for cash and technology bonus rewards, as well as shaping who controls the islands).
Upgrade your wings to boost your chance in dogfights.
Take on crew that provide you with additional bonuses.

This will be a Win 8 Desktop App.

Demo Version

The latest demo version can be down loaded via IndieDB/gamefront:

Those Magnificent Men [r006]

I should point out that IndieDB is being used to host the demos only during the development of the game. The quick authorization process enables de-bugging feedback to be performed much quicker than hosting via AppUp. I should also point out that the final version will be available via the Intel AppUp store. 

AIRCRAFT DESIGNER

Originally the game offered four distinct airframes to chose from, each specializing in a different area (cargo, passengers, weaponry and speed).  I felt this was a little frustrating to those player that wanted to execute an intermediate strategy so I have enable players to create their own aircraft by joining together airframe parts.  This allows the player to customize their airframe to their particular strategy.

The player cannot start the game by building the very best aircraft.  Aircraft can only be built based on the number of build points the player has accumulated through previous games.  Initially you can only build a simple mono-plane, but a few games in and you can progress to bi and tri-planes.


[Aircraft Designer Screen]

The latest demo, [r006] of the game introduces some new parts to use in the designer; a delta tail and a bat-style wing.

 
[New airframe parts available] 

Once the airframe has been created, the game takes a screen shot of the airframe and generates the side profile for use in the main game.

Three aspects of the code for the airframe designer that people interested in are:

  • Creation of the available parts, read-in from a txt file to enable easy modding,
  • Creation of the airframe by drag-and-dropping the available parts,
  • Creation of the in-game sprites of the custom airframe.
Part Creation 

The parts available in the designer screen are generated by reading the airframeparts.txt file. The code is contained within a single custom function, which is called as part of the screen set-up. 

function SetupUpAirframeParts()
// loads all available airframe parts into blue print mode
    row = 0
    col = 0
    AirframePartID = 0
    AvailableParts = 0
    PartsFileID = opentoread("airframeparts.txt") 

A sample of the txt file is shown here:

newpart
tail_small_01.png
tail_small_01s.png
CoGx=70.0
CoGy=50.0
Fuel=1000
Mass=35.0
Lift=1.0
Liftx=30.0
Lifty=50.0
PartType=1
SizeLeft=99
SizeRight=1
Strength=30
Value=900
endpart 

The txt file is opened is each line is read until it detects the keyword "newpart". At this point it resets all the airframe part parameters to zero.

The line following "newpart" is always the image of the part as viewed from above and the second image is always the image of the part viewed from the side. The first image is used directly in the designer screen and while flying the aircraft. The second image is only used while landing. The images are processed as follows: 

//TOP IMAGE & SPRITE
TopImageFile$ = readline(PartsFileID)
AvailableAirframePart[AirframePartID].imageid  = loadimage(TopImageFile$)
PartSpriteID = createsprite(AvailableAirframePart[AirframePartID].imageid)
AvailableAirframePart[AirframePartID].spriteid = PartSpriteID

if getspritewidth(PartSpriteID)>getspriteheight(PartSpriteID)
 setspritescale(PartSpriteID,90/getspritewidth(PartSpriteID),90/getspritewidth(PartSpriteID))
else
 setspritescale(PartSpriteID,90/getspriteheight(PartSpriteID),90/getspriteheight(PartSpriteID))
endif

setspritevisible(PartSpriteID,1)
setspritedepth(PartSpriteID,2)
fixspritetoscreen(PartSpriteID,1)
setspritex(PartSpriteID,810+((getspritewidth(AvailableAirframePart[0].spriteid )+25)*col))
setspritey(PartSpriteID,100+((getspritewidth(AvailableAirframePart[0].spriteid )+25)*row)) 

To aid the creator, text is displayed with the part to identify the key stats of the part. The text is generated as follows

// part stats
DisplayText$ = ""
repeat
    CompleteLine$ = readline(PartsFileID)
    if lower(CompleteLine$)<>"endpart" and lower(CompleteLine$)<>"none"
        stat$ = lower(GetStringToken(CompleteLine$,"=",1))
        value$ = GetStringToken(CompleteLine$,"=",2)
        select stat$
            case "cargo"
                AvailableAirframePart[AirframePartID].cargo = val(value$)
                if DisplayText$=""
                    DisplayText$ = DisplayText$+value$+" Cargo"
                else
                    DisplayText$ = DisplayText$+chr(10)+value$+" Cargo"
                endif
            endcase
            case "cogx"
                AvailableAirframePart[AirframePartID].cogx = valfloat(value$)
            endcase 

Not all part stats are added to the display text, for example the "cogx" parameter, the position of the Centre of Gravity for the part is not indicated in text, but the number of cargo units is.

Drag-And-Dropping

The airframe design screen code is set-up in a similar way to all the other screens in the game where the user can drag items from one area of the screen and drop them in another area.

Initially all the media for the screen is generated - here is an example:

// DESIGN AIRFRAME
_DesignAirframe:
// clear background
setspritevisible(titlesprite[0],0)
setspritevisible(titlesprite[1],0)
setspritevisible(titlesprite[2],0)
setspritevisible(titlesprite[3],0)
setspritevisible(MapFoldsSpt,1)

BlueprintImage = loadimage("blueprintback.png")
BlueprintSprite = createsprite(BlueprintImage)
setspritevisible(BlueprintSprite,1)
fixspritetoscreen(BlueprintSprite,1)
setspritedepth(BlueprintSprite,11)
setspritex(BlueprintSprite,40)
setspritey(BlueprintSprite,75)  

Then the main loop is executed checking for user interaction. Specifically when the pointer is first pressed, is being held or has just been released. The following code shows the complete loop showing the interact code, but with the meat of the part and sprite handling removed to help reading. 

ButtonID = 0

ActionID = 0
repeat
    // Back button pressed
    if getvirtualbuttonreleased(2)=1 then ActionID=2

    if getpointerpressed()=1
        //GRABED PART
        newselectedpart = -1
        oldselectedpart = -1
        returningsprite = 0
        sliderstarty = 0
        
        //new part
        for partid=0 to AvailableParts-1
            spriteid = AvailableAirframePart[partid].spriteid
            //CODE TO HANDLE NEW PARTS HERE
        next partid

        //existing part
        if newselectedpart=-1
            for partid=0 to 39
                spriteid = customairframepart[partid].spriteid
                //CODE TO HANDLE EXISTING PARTS HERE
            next partid
        endif

        // slider control
        if getpointerx()>794 and newselectedpart=-1 and oldselectedpart=-1
            sliderstarty=getpointery()
        endif
    endif

    if getpointerstate()=1
        //DRAGGING PART
        if (newselectedpart>-1 or oldselectedpart>-1) and returningsprite=0 and getspriteexists(clonedsprite)=1
            //move sprite

            //snap to closest part
        endif

        //SLIDER DRAGGING
        if (newselectedpart=-1 and oldselectedpart=-1 and returningsprite=0 and getspriteexists(clonedsprite)=0)
            slidervalue = slidervalue+getpointery()-sliderstarty
            sliderstarty = getpointery()
            UpdateAirframeParts(slidervalue)
        endif
    endif

    if getpointerreleased()=1
        // add to airframe
        if clonedsprite>0 and newselectedpart>-1
            if getpointerx()<792
                //ADD PART TO AIRFRAME
            else
                // remove part
            endif
        endif

        //remove part
        if clonedsprite>0 and oldselectedpart>-1 and newselectedpart<0
            if getpointerx()>792
                //Removed part
            else
                // just moving
            endif
        endif

        // DONE
        if getpointerx()>getspritex(DoneButSpt) and getpointerx()<getspritex(DoneButSpt)+getspritewidth(DoneButSpt) and clonedsprite=0
            if getpointery()>getspritey(DoneButSpt) and getpointery()<getspritey(DoneButSpt)+getspriteheight(DoneButSpt)
                // aircraft checks
                if AllGood=1 then ButtonID = 2
            endif
        endif

        // CLEAR ALL
        if getpointerx()>getspritex(ClearButSpt) and getpointerx()<getspritex(ClearButSpt)+getspritewidth(ClearButSpt) and clonedsprite=0
            if getpointery()>getspritey(ClearButSpt) and getpointery()<getspritey(ClearButSpt)+getspriteheight(ClearButSpt)
                ClearAirframeParts()
            endif
        endif
    endif

    sync()
until getrawkeypressed(13)=1 or ButtonID=2 or ActionID=2 

Sprite Creation 

When the airframe has been successfully designed the game takes 3 screen-shot images that are later used by the game. That way the game only needs to handle a single image on screen, rather than all the individual part images.

Screen shots are performed in AGK by individually calling the update(), render() and swap() functions, normally automatically called when using the sync() function. Using the GetImage(x,y,w,h) function after render() stores a section of the screen as a dedicated image that can then be saved to disk using SaveImage().

The code below shows the first images being captured and stored. This image is the main, top-down image of the aircraft using during the flying scenes. 

//Save NEW Airframe IMAGE
update(0)
render()
FileName$ = geteditboxtext(AirframeNameBox)+".png"
AFx = getspritex(BlueprintSprite)
AFy = getspritey(BlueprintSprite)
AFw = getspritewidth(BlueprintSprite)
AFh = getspriteheight(BlueprintSprite)
NewAirframeImage = getimage(AFx,AFy,AFw,AFh)
saveimage(NewAirframeImage,FileName$)
swap()

The second image is created for using within the hangar so that the airframe can be purchased, again using the top-down view. This time an additional masking sprite "SellingBackSpt" is made visible and the aircraft name is displayed before the screen shot is taken.  

// Save NEW Airframe Selling IMAGE
setspritevisible(SellingBackSpt,1)
//title
textsize = 80
settextsize(gametext.airframe,textsize)
settextstring(gametext.airframe,geteditboxtext(AirframeNameBox))
settextx(gametext.airframe,getspritex(BlueprintSprite)+(getspritewidth(BlueprintSprite)/2))
settexty(gametext.airframe,getspritey(BlueprintSprite)+(0.1*getspriteheight(BlueprintSprite)))
//re-size text if needed
if gettexttotalwidth(gametext.airframe)>getspritewidth(BlueprintSprite)
    textsize = textsize-1
    settextsize(gametext.airframe,textsize)
endif
randomcolour = random(0,5)
select randomcolour
    case 0: //red
        settextcolor(gametext.airframe,200,0,0,255)
    endcase
    case 1: //green
        settextcolor(gametext.airframe,0,200,0,255)
    endcase
    case 2: //blue
        settextcolor(gametext.airframe,0,0,200,255)
    endcase
    case 3: //magenta
        settextcolor(gametext.airframe,200,0,200,255)
    endcase
    case 4: //cyan
        settextcolor(gametext.airframe,0,200,200,255)
    endcase
    case 5: //orange
        settextcolor(gametext.airframe,200,200,0,255)
    endcase
endselect
settextvisible(gametext.airframe,1)
update(0)
render()
a=1
repeat
    FileName$ = "Airframe"+str(a)+".png"
    a = a+1
until getfileexists(FileName$)=0
AFx = getspritex(SellingBackSpt)
AFy = getspritey(SellingBackSpt)
AFw = getspritewidth(SellingBackSpt)
AFh = getspriteheight(SellingBackSpt)
NewAirframeImage = getimage(AFx,AFy,AFw,AFh)
saveimage(NewAirframeImage,FileName$)
swap()

Finally the side-view of the airframe is drawn using a custom function called DrawLandingSprite() which swaps all the top-down part images for the side profile images. It also draws the wing-struts and places the landing wheel in the correct location. 

setspritevisible(SellingBackSpt,0)
settextvisible(gametext.airframe,0)
// Save NEW Airframe Landing IMAGE
DrawLandingSprite()
FileName$ = geteditboxtext(AirframeNameBox)+"_land.png"
update(0)
render()
AFx = getspritex(BlueprintSprite)
AFy = getspritey(BlueprintSprite)
AFw = getspritewidth(BlueprintSprite)
AFh = getspriteheight(BlueprintSprite)
NewAirframeImage = getimage(AFx,AFy,AFw,AFh)
saveimage(NewAirframeImage,FileName$)
swap()

Finally all the aircraft stats, such as speed, number of passengers, gun mounts, etc. are stored to binary file with the custom suffic *.afd.

//Save NEW Airframe DATA
FileName$ = geteditboxtext(AirframeNameBox)+".afd"
SaveAirframeData(FileName$)

RANDOM MAP GENERATOR 

The islands can either be generated by random walks of varying length based on a seed value supplied by the player, taken from the system clock or taken from the player's location if their Ultrabook has its GPS turned ON.


[Map Drawing Choice]

Three sizes of maps will be available (small medium and large) with the larger sizes simply increasing the playable area, number of locations and random walks as well as the walk length. Alternatively if the player has chosen to draw their own map, then the map size limits the total number of 'blocks' that can be drawn on screen.

A separate function then draws a coastline around the random walks to improve the presentation.


[Random Map Generated with Airfield Locations]

Alternatively the player can choose to draw their own map.


[The player can draw their own map]

FLYING
Flying between locations is performed top-down looking at a map in the style of ordnance survey. The aircraft can yaw by either the arrow keys (left/right),A & D keys, or a virtual joystick on the tough screen. The throttle can also be adjusted by the arrow keys (up/down), W & S keys, or again via the touch screen. 


[Flying between airfield locations]

Occasionally flocks of birds or other passive aircraft will cross the player's path which must be avoided or they will cause damage. The player will also encounter enemy aircraft on their journey that will attempt to shoot you down. You can either attempt to shoot them down first or make a run for it. Less threateningly are cloud which also appear randomly and obscure the map, the birds and other aircraft. 


[Cloud Obscuring View while flying]

LANDING
When arriving at a location a separate landing game is started where the player must successfully land on the runway. The arrow keys (left/right), A/D keys, or the virtual joystick adjust the pitch of the aircraft which increases or reduces the lift of the aircraft. Again the throttle is adjusted by the arrow keys (up/down), W/S keys or the touch-screen changes the aircraft speed.

If the player lands too hard, damage is done to the airframe. Landing too short will incur an additional charge based the distance from the runway. If the runway is over shot, the player gets another go to land, but gets charged for a missed landing.

The landing screen is also displayed if the player is shot-down, runs out of fuel or collides with birds/aircraft and takes too much damage. The main difference being is that this is the end of the game for the player - they will have no control over their aircraft as it merrily plummets into the ground. 

[Game-Over!]

The game is about 90% complete with basic game functionality and navigation working. Most of the images are currently work-in-progress as I concentrate on the mechanics.

A video of the game play can be seen below or visit this link.

Changes in the latest Demo

[Change log for r005]

# ALL SHINY & NEW

  • Clouds! They don't do much, but they obscure your view hiding birds and other planes, so it may be worth taking a detour.
  • Keys! W,A,S & D keys can now be used for in-flight control to help the lefties of the world.
  • Economy! Stock prices are now based on stock levels and stock levels adjusted in real-time producing a more realistic economy.
  • Passengers! Becomes a sort of one-man easyJet; but with vampires; and set in 1920. 

# TWEAKED, ADJUSTED or POLISHED A BIT

  • Location names increased from 992 to 1000.
  • Paper fold effect and shaddows added.
  • Throttle backgroud changed to show control keys.
  • Groups controlling locations now restrict jobs and crew offered.
  • Small delta tail part added.
  • Small bat-style wing part added.
  • Small, Large and Intermediate passenger cabins.
  • Passenger Pod/upgrade added.
  • Changed starting position of birds.
  • Upgrade code changed so part values are no longer hard coded to help with balancing and modding.
  • Player crew capacity text added to crew quarters screen.
  • Timer based movement added to flying parts.
  • Additional coastline and mainland images added.

# REPAIRED or PATCHED UP

  • Sprite depths altered to prevent incorrect over lapping.
  • Fixed vertical descent of aircraft on GAME OVER screen.
  • Player removed from crew count.
  • Remove current crew when buying new airframe. Not ideal and will be changed at a later date.
  • Fixed duplicate sprite bug when not buying upgrades.
  • Fixed title fading when moving between between different functions. 

Background

I developed the original idea for this game as a table-top board game, but never completed development. Now having got to grips with coding, I'm able to expand on my original idea and develop this to completion. 

Points of Interest

The game employs some additional player input over the traditional mouse and keyboard:
  • The aircraft is piloted using the accelerometers and the touch-screen.
  • Making successful trips and landings only possible with real skills.
  • Access through the stock market, hanger and crew screens will be done via touch-screen or mouse cursor, whatever the player prefers.
  • The islands are created by seed values and by using the Geo-Location feature the seeds can be locked to the player's real GPS location.
    If no location data is available then a random seed is generated.
    The player also has the possibility of entering their own seed value so that seeds can be shared between players.
  • Player progress can be posted directly to Facebook and Twitter.

Web04 | 2.8.160204.4 | Advertise | Privacy
Copyright © CodeProject, 1999-2016
All Rights Reserved. Terms of Service