diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 502564d..0000000 --- a/.gitignore +++ /dev/null @@ -1,13 +0,0 @@ -# Build directory -/build/ - -# Built binary and maps -/maps/ -/ttrts - -# user files -*.user -*.sublime* -*.idea -*~ - diff --git a/CMakeLists.txt b/CMakeLists.txt deleted file mode 100644 index 97a47ba..0000000 --- a/CMakeLists.txt +++ /dev/null @@ -1,54 +0,0 @@ -cmake_minimum_required( VERSION 2.8.7 ) - -# Set version information -set( TTRTS_VERSION_MAJOR 0 ) -set( TTRTS_VERSION_MINOR 4 ) -set( TTRTS_VERSION_PATCH 0 ) - -# Set defaults for ttrts variables -set( TTRTS_MAPS "/usr/local/share/ttrts/maps/" ) -set( TTRTS_GAMES "/tmp/" ) -set( TTRTS_PORT 11715 ) - -# define these defaults in code -set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DTTRTS_MAPS=${TTRTS_MAPS}" ) -set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DTTRTS_GAMES=${TTRTS_GAMES}" ) -set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DTTRTS_PORT=${TTRTS_PORT}" ) - -# Use c++1y (14) -set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --std=c++1y" ) - -# Turn on all warnings -set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-reorder" ) - -# Turn off reorder warnings as they're kind of irrelevant -set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-reorder" ) - -# This shouldn't be needed, but it looks like IDE's like clion can forget to set -g for Debug -if( CMAKE_BUILD_TYPE MATCHES "Debug" ) - set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g" ) -endif() - -# Add bash completion to install -install( FILES scripts/ttrts_complete DESTINATION /etc/bash_completion.d/ ) - -# Add target to generate man page -# Run the gen_usage script to generate our usage header -add_custom_target( - ttrts-gen-manpage ALL - ${CMAKE_SOURCE_DIR}/scripts/gen_manpage.sh "${TTRTS_VERSION_MAJOR}" "${TTRTS_VERSION_MINOR}" "${TTRTS_VERSION_PATCH}" "ttrts.6" "${CMAKE_SOURCE_DIR}/source/README.md" -) - -# Install the ttrts man page -if( ${CMAKE_SYSTEM_NAME} MATCHES "Darwin" ) - set ( MANPAGE_LOC share/man/man6 ) -elseif( ${CMAKE_SYSTEM_NAME} MATCHES "Linux" ) - set ( MANPAGE_LOC man/man6 ) -else() - message(ERROR "Unsupported system detected") -endif() - -install( FILES "${CMAKE_BINARY_DIR}/ttrts.6" DESTINATION ${MANPAGE_LOC} ) - -# Subprojects -add_subdirectory( source ) diff --git a/README.md b/README.md deleted file mode 100644 index a6b299b..0000000 --- a/README.md +++ /dev/null @@ -1,85 +0,0 @@ -# TTRTS -*The Tiny Terminal RTS where the players write their AIs* - ------------------------------------------------------------ -## Introduction -A simple terminal based RTS game that uses text files to communicate game state and unit commands. - -TTRTS is from the ground up designed to be a fun way to practice programming. Any programming language than can handle file I/O can be used to make an AI for TTRTS, and this extensibility allows for any type of programmer to enjoy designing and playing against their friends. - ------------------------------------------------------------ -## Building TTRTS - -#### Requirements -* CMake - our build system uses cmake -* Linux/OSX - currently no support for Windows, tracked with [Issue #9](https://github.com/mdiluz/ttrts/issues/9) - -#### To Build - $ git clone https://github.com/mdiluz/ttrts.git - $ cd ttrts - $ ./bootstrap.sh - $ ./ttrts # To launch binary and display usage - ------------------------------------------------------------ -## Development - -* master branch always stores latest stable release -* master/{hotfix} branches store in progress hotfixes for the stable branch -* dev branch stores in progress development -* dev/{feature} branches store features - ------------------------------------------------------------ -## Changelog - -#### v0.4.0 -* Updated with network functionality - * Game can now be hosted with ttrts --server option - * Server can be connected to with ttrts --client -* Updated command line interface with new launcher script - * map file must now be specified with --map=FILE -* Slight refactor of libraries to account for new run targets - -#### v0.3.2 -* Fix bug when loading map files with walls -* Fix ttrts on OSX - * Install man files to correct location - * Update usage of sed to be compatible with BSD as well as GNU versions -* New maps and renames of old ones - -#### v0.3.1 -* Upgraded install target to repository - * libttrts static library binary in /usr/local/lib - * ttrts headers in /usr/local/include/ttrts - * bash completion into /etc/bash_completion.d/ - * man page into /usr/local/man/man6 - * maps into /usr/share/ttrts/maps -* client now supports env variable configuration - * TTRTS_MAPS for location of map files, defaults to /usr/share/ttrts/maps - * TTRTS_GAMES for gameplay directories, defaults to /tmp/ -* Map files now have proper header -* NOTE: This version is compatible with v0.3.0, but old generated mapfiles will need the additional header line added - -#### v0.3.0 -* Additional functionality of walls - * Walls are noted in gamestate file on new "WALL:[X,Y]..." line - * Walls are impassable by all movement -* Units leave an impassable wall behind after movement -* Game can now end if no units are able to move -* Various C++ api simplifications -* Integration of perl api from [ttrts-players](https://github.com/mdiluz/ttrts-players) - -#### v0.2.0 -* All team references changed to player - * Order file format changed to Player_#_Turn_#.txt - * Unit descriptors now use pl: instead of tm: -* Various other C++ api corrections and refactors - -#### v0.1.0 -* First playable version of ttrts - ------------------------------------------------------------ -## Further Information - -See the ttrts binary [readme](source/ttrts/README.md) for full usage and game rules - -See [ttrts-players](https://github.com/mdiluz/ttrts-players) for examples of AIs diff --git a/api/perl/ttrts.pm b/api/perl/ttrts.pm deleted file mode 100644 index 793269b..0000000 --- a/api/perl/ttrts.pm +++ /dev/null @@ -1,306 +0,0 @@ -#! /usr/bin/perl -use strict; -use warnings; - -our $ttrts_perlai_versioncompat_major = 0; -our $ttrts_perlai_versioncompat_minor = 3; - -our $headerDelimiter="~~~~"; - -our $VERBOSE = $ENV{"VERBOSE"}; - -# Format of the a gamestate header -our $headerFormatter = qr/==== ttrts v(\d+)\.(\d+)\.(\d+)+ ==== -NAME:(.+) -SIZE:\[(\d+),(\d+)\] -TURN:(\d+) -(WALL:.*?) -$headerDelimiter/; - -# Formatter for coords -our $coordFormatter = qr/\[\d+,\d+\]/; - -# Format of a unit descriptor -our $unitFormatterNonCapture = qr/UNIT:\d+ pl:\d+ vs:[^ ]+ dr:[^ ]+ ps:\[\d+,\d+\]\n?/; - -# Format of a unit descriptor -our $unitFormatter = qr/UNIT:(\d+) pl:(\d+) vs:([^ ]+) dr:([^ ]+) ps:\[(\d+),(\d+)\]\n?/; - -# Get x and y -sub getPositionsXandYString -{ - return (shift =~ /\[(\d+),(\d+)\]/); -} - -# Get all positions -sub getPositionStringsFromLine -{ - return (shift =~ /$coordFormatter/gm ); -} - -# Get information about a unit from it's descriptor -sub getUnitInfo -{ - return (shift =~ /$unitFormatter/); -} - -# Get set of units from a string -sub GetUnitStringsFromGamestate -{ - my $gamestate = shift; - - my @units = ( $gamestate =~ /$unitFormatterNonCapture/gm ); - - foreach my $unit (@units) - { - chomp($unit); - } - - return @units; -} - -# in the format $major,$minor,$patch,$name,$sizex,$sizey,$turn,$invalidpositions+ -sub GetGameInfoFromGamestate -{ - my $header = shift; - (! defined $header) and die "GetGameInfoFromGamestate was not passed valid header parameter"; - - my @info = ($header =~ /$headerFormatter/ ); - - return @info; -} - -# Get the units from a turn file -sub GetUnitStringsFromFile -{ - my $turnFile = shift or die "GetUnitStringsFromFile needs file parameter"; - - # Read in the whole file method from http://www.perlmonks.org/?node_id=1952 - my $text; - { - local $/=undef; - open FILE, $turnFile or die "Couldn't open file: $!"; - $text = ; - close FILE; - } - - return GetUnitStringsFromGamestate($text); -} - -# Check version numbers against ttrts.pm version -sub verifyVersion -{ - my $version_major = shift; - (! defined $version_major) and die "verifyVersion needs version_major parameter"; - my $version_minor = shift; - (! defined $version_minor) and die "verifyVersion needs version_minor parameter"; - if( ($version_major != $ttrts_perlai_versioncompat_major) - or ($version_minor != $ttrts_perlai_versioncompat_minor) ) - { - printf "ttrts.pm version does not match with this ttrts version\n"; - die "ttrts.pm = v$ttrts_perlai_versioncompat_minor.$ttrts_perlai_versioncompat_major ttrts = v$version_major.$version_minor"; - } -} - - -# Get information from the header for this turn -sub GetGameInfoFromFile -{ - my $turnFile = shift or die "GetGameInfoFromFile needs turnFile parameter"; - - # Read in the whole file method from http://www.perlmonks.org/?node_id=1952 - my $text; - { - local $/=undef; - open FILE, $turnFile or die "Couldn't open file: $!"; - $text = ; - close FILE; - } - - my @info = GetGameInfoFromGamestate($text); - verifyVersion @info; - - return @info; -} - -# Get units from a specific player -sub GetPlayerUnits -{ - my $thePlayer = shift; - (! defined $thePlayer) and die "GetPlayerUnits needs player parameter"; - my @allUnits = @_; - (! @allUnits) and die "GetPlayerUnits needs units parameters"; - my @myUnits; - - for my $unit (@allUnits) - { - my ($unitplayer) = $unit =~ /pl:(\d+)/; - if ( $unitplayer == $thePlayer ) - { - push(@myUnits,$unit); - } - } - - return @myUnits; -} - -sub GetTurnFileName -{ - my $turn = shift; - (! defined $turn) and die "GetTurnFileName needs turn parameter"; - my $turnFile = "Turn_TURN.txt"; - $turnFile =~ s/TURN/$turn/; - return $turnFile; -} - -sub GetCommandFileName -{ - my $turn = shift; - (! defined $turn) and die "GetCommandFileName needs turn parameter"; - my $player = shift; - (! defined $player) and die "GetCommandFileName needs player parameter"; - my $cmdFileName = "Player_PLAYER_Turn_TURN.txt"; - $cmdFileName =~ s/TURN/$turn/; - $cmdFileName =~ s/PLAYER/$player/; - return $cmdFileName; -} - -# Output the commands file -sub OutputCommandsFile -{ - my $turn = shift; - (! defined $turn) and die "OutputCommandsFile needs turn parameter"; - my $player = shift; - (! defined $player) and die "OutputCommandsFile needs player parameter"; - my $commands = shift or die "OutputCommandsFile needs commands parameter"; - - # Get output file - our $cmdFileName = GetCommandFileName($turn,$player); - - if (! -e $cmdFileName) - { - open(my $cmdFile, '>', $cmdFileName) or die "Couldn't open '$cmdFileName' $!"; - print $cmdFile $commands; - print $cmdFile "END"; - close $cmdFile; - - $VERBOSE and printf "Outputted $cmdFileName\n"; - printf "$commands"; - } - else - { - # Read in the whole file method from http://www.perlmonks.org/?node_id=1952 - my $text; - { - local $/=undef; - open FILE, $cmdFileName or die "Couldn't open file: $!"; - $text = ; - close FILE; - } - - $text =~ s/\nEND//; - - printf "Replaying $cmdFileName\n"; - printf "$text\n"; - } -} - -# Print a game map -sub PrintGameFromGamestateString -{ - my $gamestateString = shift or die "PrintGameFromGamestateString needs string parameter"; - - my @info = GetGameInfoFromGamestate($gamestateString); - my @units = GetUnitStringsFromGamestate($gamestateString); - - # $major,$minor,$patch,$name,$sizex,$sizey,$turn,$invalidpositions+ - my $gameX = $info[4]; - my $gameY = $info[5]; - - # Shift into info to where the invalid positions are stored - my @invalids = getPositionStringsFromLine($info[7]); - - my @map; - - # Fill with blanks - for my $x (0 .. $gameX-1) - { - for my $y (0 .. $gameY-1) - { - $map[$x][$y] = "-"; - } - } - - # Fill in all invalid coordinates - foreach my $coord (@invalids) - { - my @invalidPos = getPositionsXandYString($coord); - $map[$invalidPos[0]][$invalidPos[1]] = "~"; - } - - # Fill with walls - foreach my $wall ( $info[8] =~ /\[(\d+,\d+)\]/g ) - { - $wall =~ /(\d+),(\d+)/; - $map[$1][$2] = "|"; - } - - # Fill with units - for my $unit (@units) - { - my ($id,$pl,$vs,$dr,$psx,$psy) = getUnitInfo($unit); - - $pl += 31; - $vs = "\e[".$pl."m".$vs."\e[0m"; - - $map[$psx][$psy] = $vs; - } - - # Print whole map bottom left is 0,0 - for my $y ( reverse 0 .. $gameY-1 ) - { - for my $x (0 .. $gameX-1) - { - printf($map[$x][$y]); - } - printf("\n"); - } -} - -# Print a game map -sub PrintGameFromFile -{ - my $turnFile = shift or die "PrintGameFromFile needs file parameter"; - - # Read in the whole file method from http://www.perlmonks.org/?node_id=1952 - my $text; - { - local $/=undef; - open FILE, $turnFile or die "Couldn't open file: $!"; - $text = ; - close FILE; - } - - PrintGameFromGamestateString($text); -} - -# Print a turn -sub PrintGameMapForTurn -{ - my $turn = shift; - (! defined $turn) and die "PrintGameMapForTurn needs turn parameter"; - $turn = GetTurnFileName($turn); - PrintGameFromFile( $turn ); -} - -# Wait for a file to exist -sub WaitForFile -{ - my $file = shift or die "WaitForFile needs file parameter"; - while( ! -e $file ) - { - select(undef, undef, undef, 0.01); - } -} - -return 1; \ No newline at end of file diff --git a/bootstrap.sh b/bootstrap.sh deleted file mode 100755 index 701f47b..0000000 --- a/bootstrap.sh +++ /dev/null @@ -1,34 +0,0 @@ -#! /bin/bash - -# Double check for cmakelist -if [ ! -e "CMakeLists.txt" ]; then - echo "TTRTS: No source cmakelist found" - exit -fi - -# Run cmake -echo "TTRTS: Running cmake" -test ! -e build && mkdir build -cd build/ -cmake .. -if [[ $? != 0 ]]; then - echo "TTRTS: CMake failed, exiting Bootstrap" - exit -fi - -echo "TTRTS: Performing install" -sudo make install -if [[ $? != 0 ]]; then - echo "TTRTS: Install failed, check output" - exit -fi - -# Run final test to make sure -echo "TTRTS: Running tests" -./source/test/ttrts-test -if [[ $? != 0 ]]; then - echo "TTRTS: Tests failed, build must be broken" - exit -fi - -echo "TTRTS: Bootstrap complete" diff --git a/fonts/opensans-bold-webfont.eot b/fonts/opensans-bold-webfont.eot new file mode 100644 index 0000000..b5bad08 Binary files /dev/null and b/fonts/opensans-bold-webfont.eot differ diff --git a/fonts/opensans-bold-webfont.svg b/fonts/opensans-bold-webfont.svg new file mode 100644 index 0000000..1557f68 --- /dev/null +++ b/fonts/opensans-bold-webfont.svg @@ -0,0 +1,251 @@ + + + + +This is a custom SVG webfont generated by Font Squirrel. +Copyright : Digitized data copyright 20102011 Google Corporation +Foundry : Ascender Corporation +Foundry URL : httpwwwascendercorpcom + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/fonts/opensans-bold-webfont.ttf b/fonts/opensans-bold-webfont.ttf new file mode 100644 index 0000000..338220f Binary files /dev/null and b/fonts/opensans-bold-webfont.ttf differ diff --git a/fonts/opensans-bold-webfont.woff b/fonts/opensans-bold-webfont.woff new file mode 100644 index 0000000..ea6007b Binary files /dev/null and b/fonts/opensans-bold-webfont.woff differ diff --git a/fonts/opensans-bolditalic-webfont.eot b/fonts/opensans-bolditalic-webfont.eot new file mode 100644 index 0000000..d892fd9 Binary files /dev/null and b/fonts/opensans-bolditalic-webfont.eot differ diff --git a/fonts/opensans-bolditalic-webfont.svg b/fonts/opensans-bolditalic-webfont.svg new file mode 100644 index 0000000..24661f3 --- /dev/null +++ b/fonts/opensans-bolditalic-webfont.svg @@ -0,0 +1,251 @@ + + + + +This is a custom SVG webfont generated by Font Squirrel. +Copyright : Digitized data copyright 20102011 Google Corporation +Foundry : Ascender Corporation +Foundry URL : httpwwwascendercorpcom + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/fonts/opensans-bolditalic-webfont.ttf b/fonts/opensans-bolditalic-webfont.ttf new file mode 100644 index 0000000..b3eb0d3 Binary files /dev/null and b/fonts/opensans-bolditalic-webfont.ttf differ diff --git a/fonts/opensans-bolditalic-webfont.woff b/fonts/opensans-bolditalic-webfont.woff new file mode 100644 index 0000000..1712e15 Binary files /dev/null and b/fonts/opensans-bolditalic-webfont.woff differ diff --git a/fonts/opensans-extrabold-webfont.eot b/fonts/opensans-extrabold-webfont.eot new file mode 100644 index 0000000..0e88f02 Binary files /dev/null and b/fonts/opensans-extrabold-webfont.eot differ diff --git a/fonts/opensans-extrabold-webfont.svg b/fonts/opensans-extrabold-webfont.svg new file mode 100644 index 0000000..c3d6642 --- /dev/null +++ b/fonts/opensans-extrabold-webfont.svg @@ -0,0 +1,251 @@ + + + + +This is a custom SVG webfont generated by Font Squirrel. +Copyright : Digitized data copyright 2011 Google Corporation +Foundry : Ascender Corporation +Foundry URL : httpwwwascendercorpcom + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/fonts/opensans-extrabold-webfont.ttf b/fonts/opensans-extrabold-webfont.ttf new file mode 100644 index 0000000..bec521d Binary files /dev/null and b/fonts/opensans-extrabold-webfont.ttf differ diff --git a/fonts/opensans-extrabold-webfont.woff b/fonts/opensans-extrabold-webfont.woff new file mode 100644 index 0000000..a24b205 Binary files /dev/null and b/fonts/opensans-extrabold-webfont.woff differ diff --git a/fonts/opensans-italic-webfont.eot b/fonts/opensans-italic-webfont.eot new file mode 100644 index 0000000..3593c12 Binary files /dev/null and b/fonts/opensans-italic-webfont.eot differ diff --git a/fonts/opensans-italic-webfont.svg b/fonts/opensans-italic-webfont.svg new file mode 100644 index 0000000..537d20c --- /dev/null +++ b/fonts/opensans-italic-webfont.svg @@ -0,0 +1,251 @@ + + + + +This is a custom SVG webfont generated by Font Squirrel. +Copyright : Digitized data copyright 20102011 Google Corporation +Foundry : Ascender Corporation +Foundry URL : httpwwwascendercorpcom + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/fonts/opensans-italic-webfont.ttf b/fonts/opensans-italic-webfont.ttf new file mode 100644 index 0000000..ddc75c6 Binary files /dev/null and b/fonts/opensans-italic-webfont.ttf differ diff --git a/fonts/opensans-italic-webfont.woff b/fonts/opensans-italic-webfont.woff new file mode 100644 index 0000000..302cb00 Binary files /dev/null and b/fonts/opensans-italic-webfont.woff differ diff --git a/fonts/opensans-regular-webfont.eot b/fonts/opensans-regular-webfont.eot new file mode 100644 index 0000000..1c64986 Binary files /dev/null and b/fonts/opensans-regular-webfont.eot differ diff --git a/fonts/opensans-regular-webfont.svg b/fonts/opensans-regular-webfont.svg new file mode 100644 index 0000000..ead219a --- /dev/null +++ b/fonts/opensans-regular-webfont.svg @@ -0,0 +1,252 @@ + + + + +This is a custom SVG webfont generated by Font Squirrel. +Copyright : Digitized data copyright 20102011 Google Corporation +Foundry : Ascender Corporation +Foundry URL : httpwwwascendercorpcom + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/fonts/opensans-regular-webfont.ttf b/fonts/opensans-regular-webfont.ttf new file mode 100644 index 0000000..99a1ece Binary files /dev/null and b/fonts/opensans-regular-webfont.ttf differ diff --git a/fonts/opensans-regular-webfont.woff b/fonts/opensans-regular-webfont.woff new file mode 100644 index 0000000..826d643 Binary files /dev/null and b/fonts/opensans-regular-webfont.woff differ diff --git a/images/bg-ramp.jpg b/images/bg-ramp.jpg new file mode 100644 index 0000000..7738563 Binary files /dev/null and b/images/bg-ramp.jpg differ diff --git a/images/blockquote-gfx-2x.png b/images/blockquote-gfx-2x.png new file mode 100644 index 0000000..993efd5 Binary files /dev/null and b/images/blockquote-gfx-2x.png differ diff --git a/images/blockquote-gfx.png b/images/blockquote-gfx.png new file mode 100644 index 0000000..bd5be35 Binary files /dev/null and b/images/blockquote-gfx.png differ diff --git a/images/chevron-2x.png b/images/chevron-2x.png new file mode 100644 index 0000000..0ae935e Binary files /dev/null and b/images/chevron-2x.png differ diff --git a/images/chevron.png b/images/chevron.png new file mode 100644 index 0000000..65cfeda Binary files /dev/null and b/images/chevron.png differ diff --git a/images/download-fallback-bg.png b/images/download-fallback-bg.png new file mode 100644 index 0000000..aedafab Binary files /dev/null and b/images/download-fallback-bg.png differ diff --git a/images/download-sprite.png b/images/download-sprite.png new file mode 100644 index 0000000..56eedc4 Binary files /dev/null and b/images/download-sprite.png differ diff --git a/images/footer-ramp.jpg b/images/footer-ramp.jpg new file mode 100644 index 0000000..99accec Binary files /dev/null and b/images/footer-ramp.jpg differ diff --git a/images/fork-sprite.png b/images/fork-sprite.png new file mode 100644 index 0000000..0ce61b2 Binary files /dev/null and b/images/fork-sprite.png differ diff --git a/images/hr-2x.jpg b/images/hr-2x.jpg new file mode 100644 index 0000000..a883d5d Binary files /dev/null and b/images/hr-2x.jpg differ diff --git a/images/hr.jpg b/images/hr.jpg new file mode 100644 index 0000000..2dc7cef Binary files /dev/null and b/images/hr.jpg differ diff --git a/images/octocat-2x.png b/images/octocat-2x.png new file mode 100644 index 0000000..f995921 Binary files /dev/null and b/images/octocat-2x.png differ diff --git a/images/octocat.png b/images/octocat.png new file mode 100644 index 0000000..7c55dfc Binary files /dev/null and b/images/octocat.png differ diff --git a/images/ribbon-tail-sprite-2x.png b/images/ribbon-tail-sprite-2x.png new file mode 100644 index 0000000..46357a0 Binary files /dev/null and b/images/ribbon-tail-sprite-2x.png differ diff --git a/images/ribbon-tail-sprite.png b/images/ribbon-tail-sprite.png new file mode 100644 index 0000000..bd627d9 Binary files /dev/null and b/images/ribbon-tail-sprite.png differ diff --git a/images/shield-fallback.png b/images/shield-fallback.png new file mode 100644 index 0000000..be799b2 Binary files /dev/null and b/images/shield-fallback.png differ diff --git a/images/shield.png b/images/shield.png new file mode 100644 index 0000000..224425e Binary files /dev/null and b/images/shield.png differ diff --git a/images/site-2.png b/images/site-2.png new file mode 100644 index 0000000..7c55dfc Binary files /dev/null and b/images/site-2.png differ diff --git a/images/small-ribbon-tail-sprite-2x.png b/images/small-ribbon-tail-sprite-2x.png new file mode 100644 index 0000000..482649d Binary files /dev/null and b/images/small-ribbon-tail-sprite-2x.png differ diff --git a/images/small-ribbon-tail-sprite.png b/images/small-ribbon-tail-sprite.png new file mode 100644 index 0000000..f717af6 Binary files /dev/null and b/images/small-ribbon-tail-sprite.png differ diff --git a/index.html b/index.html new file mode 100644 index 0000000..d3d2cf4 --- /dev/null +++ b/index.html @@ -0,0 +1,229 @@ + + + + + + + + + + + + + + + + TTRTS by mdiluz + + + + View on GitHub +
+ +
+ + +

TTRTS

+

The Tiny Terminal RTS where the players write their AIs

+
+ + +
+
+ +
+ + download .ZIPdownload .TGZ + +
+ + + + + +
+

+TTRTS

+ +

The Tiny Terminal RTS where the players write their AIs

+ +
+ +

+Introduction

+ +

A simple terminal based RTS game that uses text files to communicate game state and unit commands.

+ +

TTRTS is from the ground up designed to be a fun way to practice programming. Any programming language than can handle file I/O can be used to make an AI for TTRTS, and this extensibility allows for any type of programmer to enjoy designing and playing against their friends.

+ +
+ +

+Building TTRTS

+ +

+Requirements

+ +
    +
  • CMake - our build system uses cmake
  • +
  • Linux/OSX - currently no support for Windows, tracked with Issue #9 +
  • +
  • perl 5.0 or newer - for the launch script
  • +
+ +

+To Build

+ +
$ git clone https://github.com/mdiluz/ttrts.git
+$ cd ttrts
+$ ./bootstrap.sh
+$ man ttrts # for full usage and guide
+
+ +
+ +

+Development

+ +
    +
  • master branch always stores latest stable release
  • +
  • master/{hotfix} branches store in progress hotfixes for the stable branch
  • +
  • dev branch stores in progress development
  • +
  • dev/{feature} branches store features
  • +
+ +
+ +

+Changelog

+ +

+v0.4.0

+ +
    +
  • Updated with network functionality + +
      +
    • Game can now be hosted with ttrts --server option
    • +
    • Server can be connected to with ttrts --client
    • +
    +
  • +
  • Updated command line interface with new launcher script + +
      +
    • map file must now be specified with --map=FILE
    • +
    +
  • +
  • Slight refactor of libraries to account for new run targets
  • +
+ +

+v0.3.2

+ +
    +
  • Fix bug when loading map files with walls
  • +
  • Fix ttrts on OSX + +
      +
    • Install man files to correct location
    • +
    • Update usage of sed to be compatible with BSD as well as GNU versions
    • +
    +
  • +
  • New maps and renames of old ones
  • +
+ +

+v0.3.1

+ +
    +
  • Upgraded install target to repository + +
      +
    • libttrts static library binary in /usr/local/lib
    • +
    • ttrts headers in /usr/local/include/ttrts
    • +
    • bash completion into /etc/bash_completion.d/
    • +
    • man page into /usr/local/man/man6
    • +
    • maps into /usr/share/ttrts/maps
    • +
    +
  • +
  • client now supports env variable configuration + +
      +
    • TTRTS_MAPS for location of map files, defaults to /usr/share/ttrts/maps
    • +
    • TTRTS_GAMES for gameplay directories, defaults to /tmp/
    • +
    +
  • +
  • Map files now have proper header
  • +
  • NOTE: This version is compatible with v0.3.0, but old generated mapfiles will need the additional header line added
  • +
+ +

+v0.3.0

+ +
    +
  • Additional functionality of walls + +
      +
    • Walls are noted in gamestate file on new "WALL:[X,Y]..." line
    • +
    • Walls are impassable by all movement
    • +
    +
  • +
  • Units leave an impassable wall behind after movement
  • +
  • Game can now end if no units are able to move
  • +
  • Various C++ api simplifications
  • +
  • Integration of perl api from ttrts-players +
  • +
+ +

+v0.2.0

+ +
    +
  • All team references changed to player + +
      +
    • Order file format changed to Player_#Turn#.txt
    • +
    • Unit descriptors now use pl: instead of tm:
    • +
    +
  • +
  • Various other C++ api corrections and refactors
  • +
+ +

+v0.1.0

+ +
    +
  • First playable version of ttrts
  • +
+ +
+ +

+Further Information

+ +

See the ttrts README for full usage and game rules

+ +

See ttrts-players for examples of AIs

+
+ + + +
+ + + + diff --git a/javascripts/headsmart.min.js b/javascripts/headsmart.min.js new file mode 100644 index 0000000..16da97a --- /dev/null +++ b/javascripts/headsmart.min.js @@ -0,0 +1 @@ +(function(a){a.fn.headsmart=function(){var c=a(this);d();function d(){var e=[],g="";if(b("h1")){e.push("h1")}if(b("h2")){e.push("h2")}if(b("h3")){e.push("h3")}if(b("h4")){e.push("h4")}if(b("h5")){e.push("h5")}if(b("h6")){e.push("h6")}for(var f=0;f0)?true:false}}})(jQuery); \ No newline at end of file diff --git a/javascripts/main.js b/javascripts/main.js new file mode 100644 index 0000000..d8135d3 --- /dev/null +++ b/javascripts/main.js @@ -0,0 +1 @@ +console.log('This would be the main JS file.'); diff --git a/javascripts/modernizr.js b/javascripts/modernizr.js new file mode 100644 index 0000000..434b0af --- /dev/null +++ b/javascripts/modernizr.js @@ -0,0 +1,4 @@ +/* Modernizr 2.5.2 (Custom Build) | MIT & BSD + * Build: http://www.modernizr.com/download/#-fontface-borderradius-boxshadow-textshadow-cssgradients-shiv-cssclasses-teststyles-testprop-testallprops-prefixes-domprefixes-load + */ +;window.Modernizr=function(a,b,c){function z(a){j.cssText=a}function A(a,b){return z(m.join(a+";")+(b||""))}function B(a,b){return typeof a===b}function C(a,b){return!!~(""+a).indexOf(b)}function D(a,b){for(var d in a)if(j[a[d]]!==c)return b=="pfx"?a[d]:!0;return!1}function E(a,b,d){for(var e in a){var f=b[a[e]];if(f!==c)return d===!1?a[e]:B(f,"function")?f.bind(d||b):f}return!1}function F(a,b,c){var d=a.charAt(0).toUpperCase()+a.substr(1),e=(a+" "+o.join(d+" ")+d).split(" ");return B(b,"string")||B(b,"undefined")?D(e,b):(e=(a+" "+p.join(d+" ")+d).split(" "),E(e,b,c))}var d="2.5.2",e={},f=!0,g=b.documentElement,h="modernizr",i=b.createElement(h),j=i.style,k,l={}.toString,m=" -webkit- -moz- -o- -ms- ".split(" "),n="Webkit Moz O ms",o=n.split(" "),p=n.toLowerCase().split(" "),q={},r={},s={},t=[],u=t.slice,v,w=function(a,c,d,e){var f,i,j,k=b.createElement("div"),l=b.body,m=l?l:b.createElement("body");if(parseInt(d,10))while(d--)j=b.createElement("div"),j.id=e?e[d]:h+(d+1),k.appendChild(j);return f=["­",""].join(""),k.id=h,m.innerHTML+=f,m.appendChild(k),l||g.appendChild(m),i=c(k,a),l?k.parentNode.removeChild(k):m.parentNode.removeChild(m),!!i},x={}.hasOwnProperty,y;!B(x,"undefined")&&!B(x.call,"undefined")?y=function(a,b){return x.call(a,b)}:y=function(a,b){return b in a&&B(a.constructor.prototype[b],"undefined")},Function.prototype.bind||(Function.prototype.bind=function(b){var c=this;if(typeof c!="function")throw new TypeError;var d=u.call(arguments,1),e=function(){if(this instanceof e){var a=function(){};a.prototype=c.prototype;var f=new a,g=c.apply(f,d.concat(u.call(arguments)));return Object(g)===g?g:f}return c.apply(b,d.concat(u.call(arguments)))};return e});var G=function(a,c){var d=a.join(""),f=c.length;w(d,function(a,c){var d=b.styleSheets[b.styleSheets.length-1],g=d?d.cssRules&&d.cssRules[0]?d.cssRules[0].cssText:d.cssText||"":"",h=a.childNodes,i={};while(f--)i[h[f].id]=h[f];e.fontface=/src/i.test(g)&&g.indexOf(c.split(" ")[0])===0},f,c)}(['@font-face {font-family:"font";src:url("https://")}'],["fontface"]);q.borderradius=function(){return F("borderRadius")},q.boxshadow=function(){return F("boxShadow")},q.textshadow=function(){return b.createElement("div").style.textShadow===""},q.cssgradients=function(){var a="background-image:",b="gradient(linear,left top,right bottom,from(#9f9),to(white));",c="linear-gradient(left top,#9f9, white);";return z((a+"-webkit- ".split(" ").join(b+a)+m.join(c+a)).slice(0,-a.length)),C(j.backgroundImage,"gradient")},q.fontface=function(){return e.fontface};for(var H in q)y(q,H)&&(v=H.toLowerCase(),e[v]=q[H](),t.push((e[v]?"":"no-")+v));return z(""),i=k=null,function(a,b){function g(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function h(){var a=k.elements;return typeof a=="string"?a.split(" "):a}function i(a){function m(){var a=j.cloneNode(!1);return k.shivMethods?(i(a),a):a}function n(a){var b=(c[a]||(c[a]=e(a))).cloneNode(!1);return k.shivMethods&&!d.test(a)?j.appendChild(b):b}var b,c={},e=a.createElement,f=a.createDocumentFragment,g=h(),j=f(),l=g.length;while(l--)b=g[l],c[b]=e(b),j.createElement(b);a.createElement=n,a.createDocumentFragment=m}function j(a){var b;return a.documentShived?a:(k.shivCSS&&!e&&(b=!!g(a,"article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio{display:none}canvas,video{display:inline-block;*display:inline;*zoom:1}[hidden]{display:none}audio[controls]{display:inline-block;*display:inline;*zoom:1}mark{background:#FF0;color:#000}")),k.shivMethods&&!f&&(b=!i(a)),b&&(a.documentShived=b),a)}var c=a.html5||{},d=/^<|^(?:button|iframe|input|script|textarea)$/i,e,f;(function(){var c,d=b.createElement("a"),g=a.getComputedStyle,h=b.documentElement,i=b.body||(c=h.insertBefore(b.createElement("body"),h.firstChild));i.insertBefore(d,i.firstChild),d.hidden=!0,d.innerHTML="",e=(d.currentStyle||g(d,null)).display=="none",f=d.childNodes.length==1||function(){try{b.createElement("a")}catch(a){return!0}var c=b.createDocumentFragment();return typeof c.cloneNode=="undefined"||typeof c.createDocumentFragment=="undefined"||typeof c.createElement=="undefined"}(),i.removeChild(d),c&&h.removeChild(c)})();var k={elements:c.elements||"abbr article aside audio bdi canvas data datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video".split(" "),shivCSS:c.shivCSS!==!1,shivMethods:c.shivMethods!==!1,type:"default",shivDocument:j};a.html5=k,j(b)}(this,b),e._version=d,e._prefixes=m,e._domPrefixes=p,e._cssomPrefixes=o,e.testProp=function(a){return D([a])},e.testAllProps=F,e.testStyles=w,g.className=g.className.replace(/(^|\s)no-js(\s|$)/,"$1$2")+(f?" js "+t.join(" "):""),e}(this,this.document),function(a,b,c){function d(a){return o.call(a)=="[object Function]"}function e(a){return typeof a=="string"}function f(){}function g(a){return!a||a=="loaded"||a=="complete"||a=="uninitialized"}function h(){var a=p.shift();q=1,a?a.t?m(function(){(a.t=="c"?B.injectCss:B.injectJs)(a.s,0,a.a,a.x,a.e,1)},0):(a(),h()):q=0}function i(a,c,d,e,f,i,j){function k(b){if(!o&&g(l.readyState)&&(u.r=o=1,!q&&h(),l.onload=l.onreadystatechange=null,b)){a!="img"&&m(function(){t.removeChild(l)},50);for(var d in y[c])y[c].hasOwnProperty(d)&&y[c][d].onload()}}var j=j||B.errorTimeout,l={},o=0,r=0,u={t:d,s:c,e:f,a:i,x:j};y[c]===1&&(r=1,y[c]=[],l=b.createElement(a)),a=="object"?l.data=c:(l.src=c,l.type=a),l.width=l.height="0",l.onerror=l.onload=l.onreadystatechange=function(){k.call(this,r)},p.splice(e,0,u),a!="img"&&(r||y[c]===2?(t.insertBefore(l,s?null:n),m(k,j)):y[c].push(l))}function j(a,b,c,d,f){return q=0,b=b||"j",e(a)?i(b=="c"?v:u,a,b,this.i++,c,d,f):(p.splice(this.i++,0,a),p.length==1&&h()),this}function k(){var a=B;return a.loader={load:j,i:0},a}var l=b.documentElement,m=a.setTimeout,n=b.getElementsByTagName("script")[0],o={}.toString,p=[],q=0,r="MozAppearance"in l.style,s=r&&!!b.createRange().compareNode,t=s?l:n.parentNode,l=!!b.attachEvent,u=r?"object":l?"script":"img",v=l?"script":u,w=Array.isArray||function(a){return o.call(a)=="[object Array]"},x=[],y={},z={timeout:function(a,b){return b.length&&(a.timeout=b[0]),a}},A,B;B=function(a){function b(a){var a=a.split("!"),b=x.length,c=a.pop(),d=a.length,c={url:c,origUrl:c,prefixes:a},e,f,g;for(f=0;f $TEMP -echo ".\" this man page is auto-generated, do not edit directly" >> $TEMP - -echo ".TH TTRTS\ v$1.$2.$3 6 $(date +%Y-%m-%d) http://mdiluz.github.io/ttrts/" >> $TEMP - -# NOTE: For the OSX version of sed we use -E, which on linux appears be an undocumented switch for -r -# we also have to use [A-Za-z] instead of \w for some reason -# as well as escaped new line characters and literal tabs instead of \n and \t - -# sections to section headers -# sub-sections in man page sub-sections -# 4-space lines to tabs -# tab starts removed -# Environment variables in bold -# User variables in italics -# remove all line-widths -# Put all back-ticks quotes in bold -# underline mapfile opt -# ensure name section uses correct -cat "$5" \ - | sed -E 's/^# ([A-Za-z]+)/.SH \1/g' \ - | sed -E 's/^##+ ([A-Za-z]+)/.SS \1/g' \ - | sed -E 's/^ (.*)$/\ - \1\ -/g' \ - | sed -E 's/^ //g' \ - | sed -E 's/\$\{([A-Za-z]+)\}/\\fB\$\1\\fR/g' \ - | sed -E 's/\{([A-Za-z]+)\}/\\fI\1\\fR/g' \ - | sed -E 's/-----+//g' \ - | sed -E 's/`(.*)`/\\fB\1\\fR/g' \ - | sed -E 's/MAPFILE/\\fImapfile\\fR/g' \ - | sed -E 's/HOSTNAME/\\fIhostname\\fR/g' \ - | sed -E 's/ ttrts -/ ttrts \\-/g' >> $TEMP - - -if [ ! -e $FILE ] || [ ! -z "$( diff $FILE $TEMP )" ]; then - mv -f $TEMP $FILE -fi diff --git a/scripts/gen_maps.sh b/scripts/gen_maps.sh deleted file mode 100755 index bb02331..0000000 --- a/scripts/gen_maps.sh +++ /dev/null @@ -1,13 +0,0 @@ -#! /bin/bash -# Use to generate the ttrts maps - -ttrtsgen=$1 - -test ! -e maps && mkdir maps # Make maps directory if needed -if [ ! -e maps ]; then - exit 1 -fi - -cd maps - -$ttrtsgen \ No newline at end of file diff --git a/scripts/gen_usage.sh b/scripts/gen_usage.sh deleted file mode 100755 index 5e33166..0000000 --- a/scripts/gen_usage.sh +++ /dev/null @@ -1,18 +0,0 @@ -#! /bin/bash -# Used to generate usage text from markdown - -FILE="$1" -TEMP="${FILE}_tmp" - -cat README.md \ - | sed -E 's/^#+ //g' \ - | sed -E 's/^ /\\t/g' \ - | sed -E 's/^ /\\t/g' \ - | sed -E 's/^/\"/' \ - | sed -E 's/$/\\n\"/' \ - > $TEMP - -# If no difference -if [ ! -e $FILE ] || [ ! -z "$( diff $TEMP $FILE )" ]; then - mv -f $TEMP $FILE -fi diff --git a/scripts/gen_version_header.sh b/scripts/gen_version_header.sh deleted file mode 100755 index aec60e2..0000000 --- a/scripts/gen_version_header.sh +++ /dev/null @@ -1,18 +0,0 @@ -HEADER="// Auto generated ttrts version header -// do not edit manually -#ifndef _TTRTS_VERSION_H_ -#define _TTRTS_VERSION_H_ - -#define TTRTS_VERSION_MAJOR $1 -#define TTRTS_VERSION_MINOR $2 -#define TTRTS_VERSION_PATCH $3 -#define TTRTS_VERSION_STRING \"v$1.$2.$3\" - -#endif //_TTRTS_VERSION_H_" - -echo "$HEADER" > "version.h.tmp" - -# If no difference -if [ ! -e version.h ] || [ ! -z "$( diff version.h version.h.tmp )" ]; then - mv -f version.h.tmp version.h -fi diff --git a/scripts/ttrts_complete b/scripts/ttrts_complete deleted file mode 100755 index d257ed4..0000000 --- a/scripts/ttrts_complete +++ /dev/null @@ -1,23 +0,0 @@ -# ttrts completion - -test ! -z TTRTS_MAPS && TTRTS_MAPS=/usr/share/ttrts/maps/ - -have ttrts && -function _ttrts -{ - commandnames="--server --client --host= --host=localhost " - for filename in ${TTRTS_MAPS}/* - do - map="${filename##*/}" - commandnames+="--map=$map " - done - - local cur prev - COMPREPLY=() - cur="${COMP_WORDS[COMP_CWORD]}" - prev="${COMP_WORDS[COMP_CWORD-1]}" - - COMPREPLY=( $(compgen -W "${commandnames}" -- ${cur}) ) -} - -complete -F _ttrts ttrts diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt deleted file mode 100644 index d73e509..0000000 --- a/source/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -# Main libraries -add_subdirectory( ttrts ) -add_subdirectory( system ) - -# Main binaries -add_subdirectory( launcher ) -add_subdirectory( client ) -add_subdirectory( server ) -add_subdirectory( local ) - -# Auxhilary binaries -add_subdirectory( test ) -add_subdirectory( gen ) \ No newline at end of file diff --git a/source/README.md b/source/README.md deleted file mode 100644 index 22b8dea..0000000 --- a/source/README.md +++ /dev/null @@ -1,121 +0,0 @@ -# NAME - ttrts - Tiny Terminal RTS - -# SYNOPSIS - ttrts [--server] [--client] [--host=HOSTNAME] [--map=MAPFILE] - -# DESCRIPTION - ttrts is a tiny terminal based RTS that uses text files as order lists to control the units - - This means that any user, program or cat that can read and write to text files can play the game - -# RETURN VALUE - ttrts will return -1 on error, or the winning player on completion - -# OPTIONS - --server - Run in server mode, must provide a map file - - --client - Run in client mode, must provide a hostname for a running server - - --map=MAPFILE - File to read in the initial game state. Local or in ${TTRTS_MAPS} - - --host=HOSTNAME - Name of host to connect to in client mode - -# USAGE - When invoked, ttrts will set up the game in a directory within ${TTRTS_GAMES} by the name of the map - - The files in this directory can be read and interpreted by human, robot or cat - - ttrts will then await order files from each participant - - Once all order files have been received ttrts will calculate the turn and output a new gamestate file - - In server and client mode, the client will output and read in these files while the server simulates the game - - This process repeats until the game is over - -# ENVIRONMENT - ${TTRTS_MAPS} - Map file lookup location, defaults to `/usr/share/ttrts/maps/` - - ${TTRTS_GAMES} - Game directory for I/O, defaults to `/tmp/` - ------------------------------------------------------------ -# FILES - `/usr/share/ttrts/maps/` holds a sample set of maps - -## Gamestate File - Turn_{TURNNUMBER}.txt - -### Contents - ===== ttrts v{MAJOR}.{MINOR}.{PATCH} ===== - NAME:{GAMENAME} - SIZE:[{X},{Y}] - TURN:{TURNNUMBER} - WALL:[{X},{Y}][{X},{Y}][{X},{Y}]...{repeat for all walls} - ~~~~ - UNIT:{ID} pl:{PLAYER} vs:{VIS} dr:{DIR(NESW)} ps:[{X},{Y}] - ... {continue for all units} - END - -## Order File - Player_{PLAYER_ID}_Turn_{TURN_NUMBER}.txt - -### Contents - ORDER:{ORDER_CHAR} id:{UNIT_ID} - ... {continue for all orders} - END - ------------------------------------------------------------ -# SERVER/CLIENT - When in server or client mode, the game can be played across a network. If desired, a player could design an AI to act as a client instead of using the client mode and intermediary filesystem. - -## Protocol - The server is accesible on port 11715 - - To perform the handshake the server will write to the socket with the format "player PLAYER_ID name GAME_NAME", it will expect this exact information to be written back to in reply. - - Once handshake is performed, the server will write to the socket in the form of the Gamestate file as above. - - The server will then wait for a new-line delimited and END terminated list of orders - - This will be repeated until the game is over - ------------------------------------------------------------ -# GAMEPLAY - - The game takes place in a series of simultaneous turns on an arbitrarily sized 2D board - - Each turn, the client outputs a gamestate file and waits for an order file from each player - - All commands are evaluated simultaneously with friendly fire enabled by default - - The game is over when any of three conditions are met - - * All remaining units are controlled by a single player - * No units are left (draw) - * All units left are unable to move (draw) - -# UNITS - Each unit occupies a single tile on the board, facing in a compass direction (NESW) - - Units will only accept orders from their owner - - Units can receive only a single order each turn - - Units cannot occupy the same tile as other units/walls - -# ORDERS -### F - Move unit [F]orward one space, leaving a wall - - This wall will remain until the end of the game, blocking movement to that tile - - Movement orders have no effect if impossible, eg. - * Attempting to move outside of map - * Attempting to move on to tile occupied by unit/wall - -### L/R - Rotate unit [L]eft or [R]ight - - Unit will rotate clockwise or counter-clockwise, this order cannot fail - -### A - [A]ttack in straight line in front of unit - - Attack will continue forward until unit can't progress, all units within the path of the attack are destroyed. diff --git a/source/client/CMakeLists.txt b/source/client/CMakeLists.txt deleted file mode 100644 index 1ae8054..0000000 --- a/source/client/CMakeLists.txt +++ /dev/null @@ -1,23 +0,0 @@ -# ====================== ttrts ======================= -# Project name -project( ttrts-client ) - -include_directories( - ${CMAKE_CURRENT_BINARY_DIR} - ../system - ../ttrts -) - -# Add the sources -set( SOURCES - client.cpp -) - -# Add the executable -add_executable( ${PROJECT_NAME} ${SOURCES} ) - -# dependent on main ttrts libary -target_link_libraries( ${PROJECT_NAME} ttrts ttrts-system ) - -# Installation target -install( TARGETS ${PROJECT_NAME} DESTINATION bin ) diff --git a/source/client/client.cpp b/source/client/client.cpp deleted file mode 100644 index 116a5a0..0000000 --- a/source/client/client.cpp +++ /dev/null @@ -1,69 +0,0 @@ -#include - -#include "net.h" -#include "game.h" -#include "error.h" -#include "filesystem.h" - -int main(int argc, char* argv[]) -{ - // must provide information - if (argc < 2) - fatal_error("Usage: ttrts-client HOST"); - - std::string hostname = argv[1]; - - sockaddr_in serv_addr; // Server address - memset(&serv_addr,0, sizeof(serv_addr)); - - // Set the server to AF_INET - serv_addr.sin_family = AF_INET; - // Set our server address port to the port number provided - serv_addr.sin_port = htons(TTRTS_PORT); - - std::cout<<"TTRTS: Connecting to "<= 0 ) - { - std::cout<<"TTRTS: Waiting for gamestate"< -#include -#include "formatters.h" - -void AddUnitToGame( player_t player, char vis, uvector2 vec, CTTRTSGame& game ) -{ - CUnit unit = CUnit::GetUnitFromVis(vis); - unit.SetPos(vec); - unit.SetPlayer(player); - game.AddUnit(std::move(unit)); -} - -void OutputGame( CTTRTSGame&& game ) -{ - std::ofstream output; - output.open (game.GetName() + ".txt"); - output << GetStringFromGame(game); - output.close(); - - __forceResetCUnitID(); -} - -int main() -{ - // Tiny 1v1 Game - //------ - //-G---- - //----R- - //-G---- - //----R- - //------ - { - CTTRTSGame game(6, 6); - game.SetName("Tiny2Player"); - - AddUnitToGame( player_t::Red, '<', uvector2(4, 2), game); - AddUnitToGame( player_t::Red, '<', uvector2(4, 4), game); - AddUnitToGame( player_t::Green, '>', uvector2(1, 1), game); - AddUnitToGame( player_t::Green, '>', uvector2(1, 3), game); - - game.AddWall(uvector2(3,2)); - game.AddWall(uvector2(3,3)); - - OutputGame(std::move(game)); - } - - // Basic 1v1 game - // -------------------- - // -G------------------ - // ------------------R- - // -G------------------ - // ------------------R- - // -G------------------ - // ------------------R- - // -G------------------ - // ------------------R- - // -G------------------ - // ------------------R- - // -------------------- - { - CTTRTSGame game(20, 12); - game.SetName("Big2Player"); - - for ( ucoord_t y : { 2,4,6,8,10 } ) - AddUnitToGame( player_t::Red, '<', uvector2(18, y), game); - for ( ucoord_t y : { 1,3,5,7,9 } ) - AddUnitToGame( player_t::Green, '>', uvector2(1, y), game); - - - OutputGame(std::move(game)); - } - - // Sort of like Chess - //GG------ - //------RR - //GG------ - //------RR - //GG------ - //------RR - //GG------ - //------RR - { - CTTRTSGame game(8, 8); - game.SetName("Chess"); - - for ( ucoord_t y : { 1,3,5,7 } ) { - AddUnitToGame(player_t::Red, '<', uvector2(6, y), game); - AddUnitToGame(player_t::Red, '<', uvector2(7, y), game); - } - - for ( ucoord_t y : { 0,2,4,6 } ) { - AddUnitToGame(player_t::Green, '>', uvector2(0, y), game); - AddUnitToGame(player_t::Green, '>', uvector2(1, y), game); - } - - OutputGame(std::move(game)); - } - - // Medium 4 player game - //---------- - //---------- - //---GGGG--- - //--R -- B-- - //--R- -B-- - //--R- -B-- - //--R -- B-- - //---YYYY--- - //---------- - //---------- - { - CTTRTSGame game(10, 10); - game.SetName("Medium4Player"); - - for ( ucoord_t y : { 2,3,4,5 } ) { - AddUnitToGame(player_t::Red, '>', uvector2(2, y), game); - AddUnitToGame(player_t::Blue, '<', uvector2(7, y), game); - } - - for ( ucoord_t x : { 2,3,4,5 } ) { - AddUnitToGame(player_t::Yellow, '^', uvector2(x,7), game); - AddUnitToGame(player_t::Green, 'v', uvector2(x,2), game); - } - - // Diagonal walls - game.AddWall(uvector2(3,3)); - game.AddWall(uvector2(3,6)); - game.AddWall(uvector2(6,3)); - game.AddWall(uvector2(6,6)); - - // middle walls - game.AddWall(uvector2(4,4)); - game.AddWall(uvector2(4,5)); - game.AddWall(uvector2(5,4)); - game.AddWall(uvector2(5,5)); - - OutputGame(std::move(game)); - } - - // Medium 3 player game - //---------- - //--------Y- - //--------Y- - //---------- - //-G-------- - //-G-------- - //---------- - //--------R- - //--------R- - //---------- - { - CTTRTSGame game(10, 10); - game.SetName("Medium3Player"); - - AddUnitToGame(player_t::Red, '<', uvector2(8, 1), game); - AddUnitToGame(player_t::Red, '<', uvector2(8, 2), game); - AddUnitToGame(player_t::Green, '>', uvector2(1, 4), game); - AddUnitToGame(player_t::Green, '>', uvector2(1, 5), game); - AddUnitToGame(player_t::Yellow, '<', uvector2(8,7), game); - AddUnitToGame(player_t::Yellow, '<', uvector2(8,8), game); - - OutputGame(std::move(game)); - } -} \ No newline at end of file diff --git a/source/launcher/CMakeLists.txt b/source/launcher/CMakeLists.txt deleted file mode 100644 index c6726c7..0000000 --- a/source/launcher/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ -# ====================== ttrts ======================= -# Project name -project( ttrts-perl-launch ) - -# Add bash completion to install -install( PROGRAMS ttrts.pl DESTINATION bin RENAME ttrts ) diff --git a/source/launcher/ttrts.pl b/source/launcher/ttrts.pl deleted file mode 100755 index 886fed6..0000000 --- a/source/launcher/ttrts.pl +++ /dev/null @@ -1,44 +0,0 @@ -#! /usr/bin/perl -# Main ttrts launcher script - -use strict; -use warnings; -use 5.0; - -use Getopt::Long qw(GetOptions); - -sub print_usage -{ - print "Unknown option: @_\n" if ( @_ ); - print "Usage: ttrts [--server] [--client] [--host=HOSTNAME] [--map=MAPFILE]\n"; - exit; -} - -our $VERBOSE = $ENV{"VERBOSE"}; - -our $server; -our $client; -our $host; -our $map; - -print_usage() if ( @ARGV < 1 or - !GetOptions( - 'client' => \$client, - 'server' => \$server, - 'host=s' => \$host, - 'map=s' => \$map, - ) ); - -# Verify we have the right parameters -print "Cannot run as both client and server\n" and exit if $client and $server; -print "Client requires hostname\n" and exit if $client and not $host; -print "Server requires mapfile\n" and exit if $server and not $map; -print "Running locally requires mapfile\n" and exit if not $server and not $client and not $map; - -# Run client, server or local -my $res = -1; -$res = system("ttrts-client $host") if $client and $host; -$res = system("ttrts-server $map") if $server and $map; -$res = system("ttrts-local $map") if not $server and not $client and $map; - -return $res \ No newline at end of file diff --git a/source/local/CMakeLists.txt b/source/local/CMakeLists.txt deleted file mode 100644 index 172b736..0000000 --- a/source/local/CMakeLists.txt +++ /dev/null @@ -1,23 +0,0 @@ -# ====================== ttrts ======================= -# Project name -project( ttrts-local ) - -include_directories( - ${CMAKE_CURRENT_BINARY_DIR} - ../system - ../ttrts -) - -# Add the sources -set( SOURCES - local.cpp -) - -# Add the executable -add_executable( ${PROJECT_NAME} ${SOURCES} ) - -# dependent on main ttrts libary -target_link_libraries( ${PROJECT_NAME} ttrts ttrts-system pthread ) - -# Installation target -install( TARGETS ${PROJECT_NAME} DESTINATION bin ) \ No newline at end of file diff --git a/source/local/local.cpp b/source/local/local.cpp deleted file mode 100644 index b2697e7..0000000 --- a/source/local/local.cpp +++ /dev/null @@ -1,62 +0,0 @@ -#include "game.h" -#include "filesystem.h" -#include "error.h" -#include "net.h" - -#include - -// ===================================================================================================================== -int main(int argc, char* argv[]) -{ - // must provide information - if (argc < 2) - fatal_error("Usage: ttrts-local MAPFILE"); - - std::string gamefile = argv[1]; - - std::cout<<"TTRTS: Launching with "< -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "net.h" -#include "filesystem.h" - -void RunServerForGame(CTTRTSGame &game) -{ - std::cout<<"TTRTS: Setting up server"< players = game.GetPlayers(); - unsigned int numClients = players.size(); - auto player_iterator = players.begin(); - - // game mutex - std::mutex gameMutex; - - // Set of clients - std::vector myClients; - - std::cout<<"TTRTS: Waiting for "< -#include -#include - -//====================================================================================================================== -// Error functions - -// For local fatal errors -inline void fatal_error(const char *msg) -{ - std::cerr< -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -// ===================================================================================================================== -// time for waiting between file stats -static const std::chrono::milliseconds sk_waitTime = std::chrono::milliseconds(100); - -// Check if a file exists -bool FileExists( const std::string& name ) -{ - struct stat buffer; - return (stat (name.c_str(), &buffer) == 0); -} - -// Wait for a file to exist -void WaitForFile( const std::string& name, const std::chrono::milliseconds& time ) -{ - while( !FileExists(name) ) std::this_thread::sleep_for(time); -} - -bool OutputGameStateFile(CTTRTSGame &game) -{ - char turnFileName[128]; - snprintf(turnFileName,128,"%s%s/Turn_%i.txt", getGamesDir().c_str(),game.GetName().c_str(),game.GetTurn()); - std::ofstream turnFile(turnFileName, std::ios_base::trunc); // truncate to overwrite if a file exists - - if ( turnFile.bad() ) - { - return false; - } - - // Output the turn description - std::string turnDescriptor = GetStringFromGame(game); - - turnFile<(file)),std::istreambuf_iterator()); - - if( gameDescriptor.size() == 0 ) - fatal_error("failed to read in any information from gamefile"); - - // Create the game - return GetGameFromString(gameDescriptor); -} - -std::string GetOrdersFromPlayerFile(const CTTRTSGame &game, player_t &player) -{ - std::string gameDir = getGamesDir(); - - char playerOrderFileName[128]; - snprintf(playerOrderFileName, 128, "%s%s/Player_%i_Turn_%i.txt", gameDir.c_str(),game.GetName().c_str(),(int) player, game.GetTurn()); - - // Wait for the player order file to be created - std::clog<<"TTRTS: Waiting for "<< playerOrderFileName << std::endl; - bool hasOrderFile = false; - while(!hasOrderFile) - { - WaitForFile(playerOrderFileName,sk_waitTime); // Wait for the file - - // File must have END - // Method taken from http://stackoverflow.com/questions/11876290/c-fastest-way-to-read-only-last-line-of-text-file - std::ifstream turnFile(playerOrderFileName); - turnFile.seekg(-1, std::ios_base::end); - - // Loop back from the end of file - bool keepLooping = true; - while(keepLooping) { - char ch; - turnFile.get(ch); // Get current byte's data - - if((int)turnFile.tellg() <= 1) { // If the data was at or before the 0th byte - turnFile.seekg(0); // The first line is the last line - keepLooping = false; // So stop there - } - else if(ch == '\n') { // If the data was a newline - keepLooping = false; // Stop at the current position. - } - else { // If the data was neither a newline nor at the 0 byte - turnFile.seekg(-2, std::ios_base::cur); // Move to the front of that data, then to the front of the data before it - } - } - - // Grab this line - std::string lastLine; - getline(turnFile,lastLine); - if(lastLine == "END") - hasOrderFile = true; - } - - std::ifstream turnFile(playerOrderFileName); - - // Reserve the full order string - std::string orders; - turnFile.seekg(0, std::ios_base::end); - orders.reserve(turnFile.tellg()); - turnFile.seekg(0, std::ios_base::beg); - - // Grab the string from the file - orders.assign((std::istreambuf_iterator(turnFile)), std::istreambuf_iterator()); - return orders; -} - -int CreateAndCleanGameDir(const std::string& gameName) -{ - std::string gameDir = getGamesDir()+gameName; - struct stat info; - int ret = stat( gameDir.c_str(), &info ); - if( ret == 0 && info.st_mode & S_IFDIR ) - { - std::cout<<"TTRTS: " << gameDir << " game directory already exists"<>input; - if( !input.size() || std::tolower(input[0]) != 'y' ) - return -1; - } - else if ( ret == 0 ) - { - fatal_error("TTRTS_GAMES exists but is not directory \nAborting..."); - } - - // Create the game directory - char cmd2[128]; - snprintf(cmd2,128, "test -d %s || mkdir %s",gameDir.c_str(),gameDir.c_str()); - if( system(cmd2) == -1) - fatal_error("Error: Failed to create the game directory"); - - // Clean out the game directory - char cmd1[128]; - snprintf(cmd1,128, "rm -rf %s/*",gameDir.c_str()); - if ( system(cmd1) == -1 ) - fatal_error("Error: Failed to clean the game directory"); - - return 0; -} - -int OutputGameEnd(const CTTRTSGame &game) { - std::cout<<"TTRTS: Game Over!"<< std::endl; - - // Get the winning player - player_t winningPlayer = game.GetWinningPlayer(); - - // Print the winner! - if ( winningPlayer != player_t::NUM_INVALID ) - { - std::cout<<"TTRTS: Winner:"<<(int) winningPlayer < -#include - -#include "game.h" - -#define STRINGIFY(x) _STRINGIFY(x) -#define _STRINGIFY(x) #x - -bool FileExists( const std::string& name ); - -void WaitForFile( const std::string& name, const std::chrono::milliseconds& time ); - -bool OutputGameStateFile(CTTRTSGame &game); - -std::string GetOrdersFromPlayerFile(const CTTRTSGame &game, player_t &player); - -CTTRTSGame GetGameFromFile( const std::string& file ); - -std::string getMapsDir(); -std::string getGamesDir(); - -int runFromFilesystem(int argc, char* argv[]); - -int CreateAndCleanGameDir(const std::string& gameName); - -#endif \ No newline at end of file diff --git a/source/system/net.cpp b/source/system/net.cpp deleted file mode 100644 index 29c23b9..0000000 --- a/source/system/net.cpp +++ /dev/null @@ -1,261 +0,0 @@ -#include "net.h" -#include "error.h" - -#include - -#include -#include - -#include -#include -#include -#include - -void WaitForOrdersFromClient(const ClientInfo info, CTTRTSGame &game, std::mutex &mut) -{ - char buffer[1028]; // buffer for orders - - std::clog<<"TTRTS: Waiting for player "<<(int)info.player<<" at "< &myClients, CTTRTSGame &game, std::mutex &gameMutex) -{ - // Spawn threads - std::vector clientThreads; - for(auto client : myClients) - { - std::thread clientThread(WaitForOrdersFromClient, client, std::ref(game), ref(gameMutex)); - clientThreads.push_back(move(clientThread)); - } - - // Join up all the threads - for ( std::thread& thread : clientThreads ) - { - thread.join(); - } -} - -void SendGamestateToClients(std::vector &myClients, const CTTRTSGame &game, std::mutex &gameMutex) -{ - gameMutex.lock(); - std::string gamestate_string = GetStringFromGame(game); - gameMutex.unlock(); - - for (auto client : myClients) - { - // Write to the socket with the buffer - if ( write( client.clientsockfd, gamestate_string.c_str(), gamestate_string.length() ) < 0 ) - fatal_perror("ERROR sending to client"); - } -} - - -void PerformClientHandshake(int sockfd, unsigned int &player, std::string &gameNameString) -{ - char handshakeBuffer[128]; - memset(handshakeBuffer,0,sizeof(handshakeBuffer)); - - if (read(sockfd, handshakeBuffer,sizeof(handshakeBuffer)-1) < 0) - fatal_perror("ERROR recieving handshake from server"); - - std::string handshake(handshakeBuffer); - - if ( write( sockfd, handshake.c_str(), handshake.length()+1 ) < 0 ) - fatal_perror("ERROR sending handshake to server"); - - char gameName[64]; - if ( sscanf(handshake.c_str(),TTRTS_HANDSHAKE_FORMAT,&player,gameName) < 2 ) - fatal_error("Handshake failed"); - - gameNameString = gameName; -} - -void PerformServerHandshake(const ClientInfo &client, const std::string &game) -{ - char handshake[64]; - snprintf(handshake, sizeof(handshake), TTRTS_HANDSHAKE_FORMAT,(unsigned int)client.player,game.c_str()); - - // Send handshake - if ( write( client.clientsockfd,handshake,sizeof(handshake) ) < 0 ) - fatal_perror("ERROR sending to client"); - - // Receive handshake - char buffer[64]; - if ( read(client.clientsockfd,buffer,sizeof(buffer)-1) < 0 ) - fatal_perror("ERROR reading from client"); - - // Verify handshake - if ( std::string(buffer) != std::string(handshake) ) - fatal_error("Error in client handshake"); - - std::clog<<"TTRTS: Success on handshake with player "<<(int)client.player<< std::endl; -} - -void TryBindSocket(int sockfd, const sockaddr_in &serv_addr) -{ - std::clog<<"TTRTS: Binding to socket"<< std::endl; - int retry = 1; - while (1) - { - if(retry > 10) - fatal_error("Binding failed"); - - // Attempt to bind our listening socket - if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) >= 0) - break; - - std::cerr<<"Warning: Binding failed on try "<h_addr, server->h_length); - - // Attempt to connect to the server using the socket and server address info - if (connect(sockfd, (const sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) - fatal_perror("ERROR connecting"); - - return sockfd; -} - -std::string WaitForGamestateMessage(int sockfd) -{ - std::string gamestate; - char gamestateBuffer[1028]; - while( gamestate.find("END") == std::string::npos ) - { - memset(gamestateBuffer,0,sizeof(gamestateBuffer)); - - // Receive gamestate - if (read(sockfd,gamestateBuffer,sizeof(gamestateBuffer)-1) < 0) - fatal_perror("ERROR reading from client"); - - gamestate+=gamestateBuffer; - } - return gamestate; -} - -int SendOrdersToServer(int sockfd, const std::string &orders) -{ - int n = write(sockfd,orders.c_str(),orders.length()); - if (n < 0) - fatal_perror("ERROR writing to socket"); - return n; -} - - -int OutputGameEnd( CTTRTSGame& game ) -{ - std::cout<<"TTRTS: Game Over!"< -#include - -#include -#include - -#include -#include -#include -#include - -#include -#include -#include - -#define TTRTS_HANDSHAKE_FORMAT "player %u name %s" - -//====================================================================================================================== -// Structs for net management - -// Struct for net client info -struct ClientInfo -{ - sockaddr_in cli_addr; - int clientsockfd; - player_t player; -}; - - -//====================================================================================================================== -// Server side function - -// Get the address of a local server -sockaddr_in GetLocalServerAddress(); - -// Set up a new listening socket for the server -int SetUpServerListeningSocket(const sockaddr_in &serv_addr); - -// Wait for client connection on listening socket sockfd -// Will fill clientInfo with client information -ClientInfo &WaitForClientConnection(int sockfd, const std::string &game, ClientInfo &clientInfo); - -// Wait for orders from a client, will not return until client has send valid orders -// Will automatically add orders to the game -void WaitForOrdersFromClient(const ClientInfo info, CTTRTSGame &game, std::mutex &mut); - -// Iterates through a list of clients calling WaitForOrdersFromClient -void WaitForOrdersFromClients(std::vector &myClients, CTTRTSGame &game, std::mutex &gameMutex); - -// Sends current gamestate to each client -void SendGamestateToClients(std::vector &myClients, const CTTRTSGame &game, std::mutex &gameMutex); - -// Tries to bind to a socket, will attempt 10 times with longer waits between -void TryBindSocket(int sockfd, const sockaddr_in &serv_addr); - -// Perform the server side handshake with a client -void PerformServerHandshake(const ClientInfo &client, const std::string &game); - -//====================================================================================================================== -// Client side functions - -// Connect to the host, returns new socket for communication -int ConnectToHostServer(const std::string &hostname, sockaddr_in &serv_addr); - -// Perform the client side handshake with the server -void PerformClientHandshake(int sockfd, unsigned int &player, std::string &gameNameString); - -// Wait for gamestate message from host -std::string WaitForGamestateMessage(int sockfd); - -// Send orders to the server -int SendOrdersToServer(int sockfd, const std::string &orders); - -//====================================================================================================================== -// Other functions -int OutputGameEnd( CTTRTSGame& game ); - -#endif \ No newline at end of file diff --git a/source/test/CMakeLists.txt b/source/test/CMakeLists.txt deleted file mode 100644 index 3e6a60c..0000000 --- a/source/test/CMakeLists.txt +++ /dev/null @@ -1,17 +0,0 @@ - -# ====================== tests ======================= -# Project name -project( ttrts-test ) - -include_directories( - ../ttrts -) - -set( SOURCES - test.cpp -) - -# Add the executable -add_executable( ttrts-test ${SOURCES} ) - -target_link_libraries( ttrts-test ttrts ) diff --git a/source/test/test.cpp b/source/test/test.cpp deleted file mode 100644 index 5cbb700..0000000 --- a/source/test/test.cpp +++ /dev/null @@ -1,205 +0,0 @@ -#include -#include // std::cout - -#include "order.h" -#include "game.h" - -const char* tests() -{ - // Test if we can properly set a unit's visual - { - CUnit unit; - unit.SetFromVisual('v'); - if(unit.GetVisual() != 'v' ) - return "failed to properly create V unit"; - } - - // Test unique unit IDs - { - CUnit unit; - CUnit unit2; - if(unit.GetID() == unit2.GetID() ) - return "Unit IDs the same"; - } - - // Test basic invalid unit conversion - { - CUnit unit1; - - std::string unit1Desc = GetStringFromUnit(unit1); - CUnit unit2 = GetUnitFromString(unit1Desc); - - if ( unit1 != unit2 ) - return "Failed to convert an empty unit to string and back"; - } - - // Test custom unit conversion - { - CUnit unit1; - unit1.SetFromVisual('v'); - unit1.SetPlayer(player_t::Green); - unit1.SetPos(uvector2(5, 10)); - - std::string unit1Desc = GetStringFromUnit(unit1); - CUnit unit2 = GetUnitFromString(unit1Desc); - - if ( unit1 != unit2 ) - return "Failed to convert custom unit to string and back"; - } - - // Test if we can successfully create a unit from a visual - { - CUnit unit = CUnit::GetUnitFromVis('v'); - if(unit.GetVisual() != 'v' ) - return "failed to properly create V unit with factory"; - } - - // Test if we can successfully convert orders back and forth - { - SOrder order; - order.command = command_c::F; - order.unit = 10; - std::string order_string = GetStringFromOrder(order); - SOrder order2 = GetOrderFromString(order_string); - - if ( order2 != order ) - return "failed order string conversion test"; - } - - // Test of the game can logically handle a blank game - { - CTTRTSGame game( 15, 10 ); - if( game.SimulateToNextTurn() ) - return "Failed to simulate a blank game"; - - if( game.GetNumUnits() ) - return "Game started with non-zero unit number"; - } - - // Test if the game correctly rejects units placed ontop of others - { - CTTRTSGame game( 5, 5 ); - - { - CUnit unit = CUnit::GetUnitFromVis('^'); - unit.SetPos({2, 2}); - unit.SetPlayer(player_t::Red); - - game.AddUnit(std::move(unit)); - } - - { - CUnit unit = CUnit::GetUnitFromVis('^'); - unit.SetPos({2, 2}); - unit.SetPlayer(player_t::Red); - - if( !game.AddUnit(std::move(unit)) ) - return "Game should have rejected unit placed on the same spot"; - - if( game.GetNumUnits() != 1 ) - return "Game ended up with too many units"; - } - } - - // Test on a small board if a movement command succeeds correctly - { - CTTRTSGame game( 5, 5 ); - - CUnit unit = CUnit::GetUnitFromVis('>'); - const unit_id_t id = unit.GetID(); - SOrder order; - - unit.SetPos({2, 2}); - unit.SetPlayer(player_t::Red); - - if ( game.AddUnit(std::move(unit)) ) - return "Game failed to add valid unit"; - - order.unit = id; - order.command = command_c::F; - - if( game.IssueOrder(player_t::Red,order) ) - return "Game failed to issue valid order"; - - if (game.SimulateToNextTurn() ) - return "Game failed to simulate valid turn"; - - if(game.GetUnitByIDConst(id).GetPos() != uvector2{3,2} ) - return "Simple movement order failed"; - - } - - // Test on a tiny board, whether a unit can correctly attack another - { - CTTRTSGame game( 2, 1 ); - game.SetName("Test_578"); - - unit_id_t id; - { - CUnit unit = CUnit::GetUnitFromVis('>'); - id = unit.GetID(); - SOrder order; - - unit.SetPos({0, 0}); - unit.SetPlayer(player_t::Blue); - - if ( game.AddUnit(std::move(unit)) ) - return "Game failed to add valid unit"; - - order.unit = id; - order.command = command_c::A; - - if( game.IssueOrder(player_t::Blue,order) ) - return "Game failed to issue valid order"; - } - { - CUnit unit = CUnit::GetUnitFromVis('<'); - - unit.SetPos({1, 0}); - unit.SetPlayer(player_t::Red); - - if ( game.AddUnit(std::move(unit)) ) - return "Game failed to add valid unit"; - } - - game.SimulateToNextTurn(); - - if ( game.GetNumUnits() != 1 ) - return "Game failed to kill a unit when it logically should have"; - - if (game.GetUnitByIndex(0).GetDir() != dir_c::E ) - return "Game killed the wrong unit"; - - if (game.GetUnitByIndex(0).GetID() != id ) - return "Game killed the wrong unit"; - - if ( game.GetWinningPlayer() != player_t::Blue ) - return "Game failed to recognise a win for the right Player"; - - std::string game_string = GetStringFromGame(game); - CTTRTSGame game2 = GetGameFromString(game_string); - - std::string game2_string = GetStringFromGame(game2); - - // Try matching up the game descriptors - if( game_string != game2_string ) - return "Generating new game from string failed"; - - } - - return 0; -} - -// Main program entry point -int main() -{ - const char* res = tests(); - - if( res ) - { - std::cout<<"ERROR: "< - -#include "version.h" - -// Get the game information as a string -std::string GetStringFromGame( const CTTRTSGame& game ) -{ - // Grab the walls - std::string walls; - if( game.GetWalls().size() == 0 ) - { - walls = "NONE"; - } - - for ( auto wall : game.GetWalls() ) - { - char pos[16]; - if( snprintf(pos, 16, GAME_POS_FORMATTER , wall.x, wall.y ) < 0 ) - { - return "BUFFER OVERFLOW"; - } - walls += pos; - } - - - // Print out the header - char header[512]; - if ( snprintf(header, 512, GAME_HEADER_FORMATTER , - TTRTS_VERSION_MAJOR, - TTRTS_VERSION_MINOR, - TTRTS_VERSION_PATCH, - game.GetName().c_str(), - game.GetDimensions().x, - game.GetDimensions().y, - game.GetTurn(), - walls.c_str() ) < 0 ) - { - return "BUFFER OVERFLOW"; - } - - // Gather unit information - std::string units; - for ( const SOrderUnitPair & pair : game.GetOrderUnitPairs() ) - { - units += GetStringFromUnit(pair.unit); - units += '\n'; - } - - // Append the header and units - std::string state(header); - state += '\n'; - state += GAME_HEADER_DELIMITER; - state += units; - state += "END"; - - return state; -} - -// Get the game information as a string -CTTRTSGame GetGameFromString( const std::string& input ) -{ - size_t headerEnd = input.find(GAME_HEADER_DELIMITER); - - std::string header = input.substr(0, headerEnd); - std::string units = input.substr(headerEnd + strlen(GAME_HEADER_DELIMITER)); - - // Grab information from the header - unsigned int major; - unsigned int minor; - unsigned int patch; - char name[64]; - unsigned int turn; - unsigned int sizex; - unsigned int sizey; - char walls[512]; - if( sscanf(header.c_str(), GAME_HEADER_FORMATTER, &major, &minor, &patch, name, &sizex, &sizey, &turn, walls) != 8 ) - { - std::cerr<<"Error: Failed to properly read game state from text"< walls_vector; - { - std::string walls_str = walls; - size_t pos; - while ( ( pos = walls_str.find(']') ) != std::string::npos ) - { - std::string pos_string = walls_str.substr(0,pos+1); - - // Use scanf to extract positions - - unsigned int x; - unsigned int y; - if( sscanf(pos_string.c_str(), GAME_POS_FORMATTER, &x, &y ) != 2 ) - { - return CTTRTSGame(0,0); - } - - // Erase this coordinate - walls_str.erase(0,pos+1); - - // Append our list - walls_vector.push_back({(ucoord_t)x,(ucoord_t)y}); - } - } - - CTTRTSGame game(sizex,sizey); - game.SetName(name); - game.SetTurn(turn); - - // For each line, construct a unit - { - size_t pos; - while ((pos = units.find('\n')) != std::string::npos) { - std::string unit_string = units.substr(0, pos); - units.erase(0, pos + 1); - game.AddUnit(GetUnitFromString(unit_string)); - } - } - - // Add all walls - for ( auto wall : walls_vector) - { - game.AddWall(wall); - } - - return game; -} - -// Get a string descriptor of a unit -std::string GetStringFromUnit(const CUnit& unit ) -{ - static char buff[128]; - memset(buff,0,sizeof(buff)); - - snprintf(buff,128, UNIT_FORMATTER, - unit.GetID(), - (int)unit.GetPlayer(), - unit.GetVisual(), - unit.GetDir(), - unit.GetPos().x, - unit.GetPos().y ); - - return buff; -} - -// Get a unit from a string descriptor -CUnit GetUnitFromString(const std::string& unit ) -{ - CUnit ret; - - unsigned int id; - int player; - char vis; - char dir; - unsigned int posx; - unsigned int posy; - - sscanf(unit.c_str(), UNIT_FORMATTER, - &id, - &player, - &vis, - &dir, - &posx, - &posy ); - - ret.ForceSetID((unit_id_t)id); - ret.SetPlayer((player_t) player); - ret.SetVisual((unitvis_c)vis); - ret.SetDir((dir_c)dir); - ret.SetPos(uvector2(posx,posy)); - - return ret; -} - -// Convert an order to a string -std::string GetStringFromOrder(const SOrder & order ) -{ - static char buff[128]; - memset(buff,0,sizeof(buff)); - - snprintf(buff,128, ORDER_FORMATTER, - order.command, - order.unit); - - return buff; -} - -// Convert a string to an order -SOrder GetOrderFromString( const std::string& order ) -{ - SOrder ret; - - char corder; - unsigned int unit; - - sscanf(order.c_str(), ORDER_FORMATTER, - &corder, - &unit); - - ret.command = (command_c)corder; - ret.unit = unit; - - return ret; -} diff --git a/source/ttrts/formatters.h b/source/ttrts/formatters.h deleted file mode 100644 index 31cf9e7..0000000 --- a/source/ttrts/formatters.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef _TTRTS_FORMATTERS_H_ -#define _TTRTS_FORMATTERS_H_ - -#include "order.h" -#include "game.h" -#include "unit.h" - -#include "string.h" - -#define GAME_POS_FORMATTER "[%u,%u]" - -#define GAME_HEADER_FORMATTER "==== ttrts v%u.%u.%u ====\nNAME:%s\nSIZE:" GAME_POS_FORMATTER "\nTURN:%u\nWALL:%s" -#define GAME_HEADER_DELIMITER "~~~~\n" - -#define UNIT_FORMATTER "UNIT:%u pl:%u vs:%c dr:%c ps:" GAME_POS_FORMATTER - -// order <--> string conversion functions -std::string GetStringFromOrder(const SOrder & order ); -SOrder GetOrderFromString( const std::string& order ); - -// game <--> string conversion functions -CTTRTSGame GetGameFromString( const std::string& input ); -std::string GetStringFromGame( const CTTRTSGame& game ); - -// unit <--> string conversion functions -std::string GetStringFromUnit(const CUnit& unit ); -CUnit GetUnitFromString(const std::string& unit ); - -#endif \ No newline at end of file diff --git a/source/ttrts/game.cpp b/source/ttrts/game.cpp deleted file mode 100644 index d649060..0000000 --- a/source/ttrts/game.cpp +++ /dev/null @@ -1,532 +0,0 @@ -#include "game.h" - -#include -#include -#include "formatters.h" - -CTTRTSGame::CTTRTSGame( ucoord_t c, ucoord_t r ) -: dimensions( c,r ) -, turn (0), name ( "Custom_Game" ) -{ - -} - -// Move constructor -CTTRTSGame::CTTRTSGame(CTTRTSGame&& game) -: m_OrderUnitPairs(std::move(game.m_OrderUnitPairs)) -, dimensions(std::move(game.dimensions)) -, turn(std::move(game.turn)) -, name(std::move(game.name)) -, m_walls(std::move(game.m_walls)) -{ - -} - -CTTRTSGame& CTTRTSGame::operator=(CTTRTSGame&& game) -{ - m_OrderUnitPairs = std::move(game.m_OrderUnitPairs); - dimensions = std::move(game.dimensions); - turn = std::move(game.turn); - name = std::move(game.name); - return *this; -} - -// Interpret a string of orders -int CTTRTSGame::IssueOrders( player_t player, const std::string& _orders ) -{ - COrderVector orderVector; - - // Copy the const orders into a buffer we can edit - std::string orders = _orders; - - // Find a line end - size_t pos; - while ( (pos = orders.find('\n')) != std::string::npos ) - { - // Grab the string up to the line end - const std::string sorder = orders.substr(0, pos); - - // Erase all of string up to and including the line end - orders.erase(0,pos+1); - - // Create an order from the string and push it back - SOrder order = GetOrderFromString( sorder ); - orderVector.push_back(order); - } - - // Call our add order by vector method - return IssueOrders(player,orderVector); -} - -// Issue orders by vector to the game -int CTTRTSGame::IssueOrders( player_t player, const COrderVector& orders ) -{ - // verify all the orders - for ( auto order : orders ) - { - // If any order returns non-zero, back out - if ( IssueOrder(player,order) ) - return 1; - } - - return 0; -} - -// Issue a single order -int CTTRTSGame::IssueOrder( player_t player, const SOrder & order ) -{ - // Verify the order - if ( VerifyOrder(player,order) ) - return 1; - - // Get the right unit for the order - for ( SOrderUnitPair & pair : m_OrderUnitPairs ) - { - if (pair.unit.GetID() == order.unit ) - { - pair.order = order; - return 0; - } - } - - // Unit was not found, return 2 - return 2; -} - -// Verify a position -int CTTRTSGame::VerifyPosIsValidMovement(uvector2 vec) const -{ - // Simply check if within the bounds of our dimensions for now - if ( ( vec.x >= dimensions.x ) - || ( vec.y >= dimensions.y ) ) - { - return 1; - } - - // Check within our invalid positions - for ( const uvector2& invalid : m_walls) - { - if( vec == invalid ) - { - return 2; - } - } - - return 0; -} - - -// Get a units new position -uvector2 CTTRTSGame::GetNewPosition( const SOrderUnitPair & pair ) const -{ - // Grab the order - switch ( pair.order.command) - { - // For forward orders, grab in front - case command_c::F: - return pair.unit.GetInFront(); - // For all other orders, just grab the old position - default: - return pair.unit.GetPos(); - } -} - -// Simulate and progress to the next turn -// Returns non-zero if simulation failed -int CTTRTSGame::SimulateToNextTurn() -{ - int error = 0; - - // Attempt all movement orders - for ( SOrderUnitPair & pair : m_OrderUnitPairs ) - { - switch ( pair.order.command) - { - case command_c::F: - { - // Verify new unit position will be on the board - uvector2 newpos = GetNewPosition(pair); - - // Verify the position is even available - bool possible = (VerifyPosIsValidMovement(newpos) == 0 ); - - if ( possible ) - { - // If any unit is in this spot, or moving unit moving to said spot, reject this - for ( const SOrderUnitPair & pair2 : m_OrderUnitPairs ) - { - // Skip myself - if(pair.unit.GetID() == pair2.unit.GetID() ) continue; - - if( GetNewPosition(pair2) == newpos ) - { - possible = false; - break; - } - } - } - - // If the movement is still possible - if ( possible ) - { - // Create a wall at our old position - AddWall(pair.unit.GetPos()); - pair.unit.SetPos(newpos); - } - } - break; - default: - break; - } - } - - // Turn all units that need turning - for ( SOrderUnitPair & pair : m_OrderUnitPairs ) - { - switch ( pair.order.command) - { - case command_c::L: - { - // Simply turn left - pair.unit.TurnLeft(); - } - break; - case command_c::R: - { - // Simply turn right - pair.unit.TurnRight(); - } - break; - default: - break; - } - } - - // Iterate through all charge states - bool charging = true; - while(charging) - { - // Assume no more charging - charging = false; - // Initially move all units - for ( SOrderUnitPair & pair : m_OrderUnitPairs ) - { - if ( pair.order.command == command_c::A ) - { - uvector2 newpos = pair.unit.GetInFront(); - // If move would be within the arena - if (VerifyPosIsValidMovement(newpos) == 0 ) - { - pair.unit.SetPos(newpos); - - // Unit moved, so more charging needs to be done - charging = true; - } - } - } - - std::vector< unit_id_t > toKill; // Vector to store which units to kill - - // Initially move all units to check for pass through - for ( SOrderUnitPair & pair1 : m_OrderUnitPairs ) - if ( pair1.order.command == command_c::A ) - for ( SOrderUnitPair & pair2 : m_OrderUnitPairs ) - if (pair1.unit.GetID() != pair2.unit.GetID() // Don't check the same units - && pair2.order.command == command_c::A ) - { - if( CheckForPassThrough(pair1.unit,pair2.unit) ) - { - toKill.push_back(pair1.unit.GetID()); - toKill.push_back(pair2.unit.GetID()); - } - } - - // Kill all units to kill - KillAll(toKill); - toKill.clear(); - - // Check for all matching spots - for ( SOrderUnitPair & pair1 : m_OrderUnitPairs ) - for ( SOrderUnitPair & pair2 : m_OrderUnitPairs ) - { - if(pair1.unit.GetID() == pair2.unit.GetID() ) continue; // Don't check the same units - - if(pair1.unit.GetPos() == pair2.unit.GetPos() ) - { - if( pair1.order.command == command_c::A ) - { - toKill.push_back(pair2.unit.GetID()); - } - - if( pair2.order.command == command_c::A ) - { - toKill.push_back(pair1.unit.GetID()); - } - } - } - - // Kill all units to kill - KillAll(toKill); - toKill.clear(); - } - - // Clear all orders - for ( SOrderUnitPair & pair : m_OrderUnitPairs ) - pair.order = SOrder(); - - // Increment the current turn - turn++; - - return error; -} - - -// Kill all units in list -void CTTRTSGame::KillAll( std::vector< unit_id_t >& vec ) -{ - // Sort and erase all duplicates - std::sort( vec.begin(), vec.end() ); - vec.erase( std::unique( vec.begin(), vec.end() ), vec.end() ); - for ( auto id : vec ) - { - for ( OrderUnitPairVector::iterator it = m_OrderUnitPairs.begin(); - it != m_OrderUnitPairs.end(); - it++ ) - { - if((*it).unit.GetID() == id ) - { - // Remove the unit from our alive unit pairs - m_OrderUnitPairs.erase(it); - break; - - } - } - } -} - -// Check if two units passed through each other -bool CTTRTSGame::CheckForPassThrough( const CUnit& one, const CUnit& two ) -{ - uvector2 pos1 = one.GetPos(); - uvector2 pos2 = two.GetPos(); - dir_c dir1 = one.GetDir(); - dir_c dir2 = two.GetDir(); - - if( pos1.x == pos2.x ) { // Same col - if (pos1.y == (pos2.y + 1)) { - if (dir1 == dir_c::N && dir2 == dir_c::S) - return true; - } - else if (pos1.y == (pos2.y - 1)) { - if (dir1 == dir_c::S && dir2 == dir_c::N) - return true; - } - } - else if( pos1.y == pos2.y ) { // Same row - if( pos1.x == (pos2.x+1) ) { - if( dir1 == dir_c::E && dir2 == dir_c::W ) - return true; - } - else if( pos1.x == (pos2.x-1) ) { - if( dir1 == dir_c::E && dir2 == dir_c::W ) - return true; - } - } - - return false; -} - -// Add a unit, nonzero return value indicates error -int CTTRTSGame::AddUnit( CUnit&& unit ) -{ - // Verify the unit - if( !unit.Valid() ) - return 1; - - // Verify if the unit can be placed on the current board - const uvector2 pos = unit.GetPos(); - if( (pos.x >= dimensions.x) || (pos.y >= dimensions.y) ) - return 2; - - // If any unit's position matches, reject this - for ( const SOrderUnitPair & pair: m_OrderUnitPairs ) - { - if(pair.unit.GetPos() == unit.GetPos() ) - return 3; - } - - // Add the unit with a blank order - m_OrderUnitPairs.push_back( SOrderUnitPair(std::move(unit), SOrder()) ); - - - return 0; -} - -// Add a units, nonzero return value indicates error -int CTTRTSGame::AddUnits( CUnitVector&& units ) -{ - CUnitVector::iterator it; - - for ( it = units.begin(); it != units.end(); it++ ) - { - // Attempt the unit add - if ( AddUnit( std::move(*it) ) ) - return 1; - } - - // All units added successfully - return 0; -} - -// Verify any order -int CTTRTSGame::VerifyOrder( player_t player, const SOrder & order ) const -{ - int ret = 1; - - // Grab the unit ID - const unit_id_t unitID = order.unit; - - // Attempt to find the unit - for ( const SOrderUnitPair & pair : m_OrderUnitPairs ) - { - // Accept if we have the unit - if (pair.unit.GetID() == unitID - && pair.unit.GetPlayer() == player) - { - ret = 0; - break; - } - } - - // for now, as long as the unit exists we can attempt the order - return ret; -} - -// Get unit by unit ID -const CUnit& CTTRTSGame::GetUnitByIDConst( unit_id_t id ) const -{ - for ( const SOrderUnitPair & pair : m_OrderUnitPairs ) - { - // Attempt the unit add - if (pair.unit.GetID() == id ) - return pair.unit; - } - - // Return an invalid unit - static CUnit invalid_unit; - return invalid_unit; -} - -// Get an order by unit ID -const SOrder & CTTRTSGame::GetOrderByIDConst( unit_id_t id ) const -{ - for ( const SOrderUnitPair & pair : m_OrderUnitPairs ) - { - // Attempt the unit add - if (pair.unit.GetID() == id ) - return pair.order; - } - - // Return an invalid unit - static SOrder invalid_order; - return invalid_order; -} - -// Get unit by unit ID -CUnit& CTTRTSGame::GetUnitByID( unit_id_t id ) -{ - for ( SOrderUnitPair & pair : m_OrderUnitPairs ) - { - // Attempt the unit add - if (pair.unit.GetID() == id ) - return pair.unit; - } - - // Return an invalid unit - static CUnit invalid_unit; - return invalid_unit; -} - -// Get a vector of the players in the current game -std::vector CTTRTSGame::GetPlayers() const -{ - std::vector players; - players.reserve(GetNumUnits()); - - // Grab all players - for ( const SOrderUnitPair & pair : m_OrderUnitPairs ) - { - players.push_back(pair.unit.GetPlayer()); - } - - // Remove dupes - std::sort( players.begin(), players.end() ); - players.erase( std::unique( players.begin(), players.end() ), players.end() ); - - return players; -} - -// Check if we have a win state -player_t CTTRTSGame::GetWinningPlayer() const -{ - // Array of units for each Player - unsigned int units[(int) player_t::NUM_INVALID]; - memset(units,0,sizeof(units)); - - // Count up all the units for each Player - for ( const SOrderUnitPair & pair : m_OrderUnitPairs ) - { - const int player = (int) pair.unit.GetPlayer(); - units[player] += 1; - } - - // Default winning Player to invalid (no win) - player_t winningPlayer = player_t::NUM_INVALID; - - // For each of the players - for ( unsigned int i = 0; i < _countof(units); i++ ) - { - // if there are still units in this Player, and the winning Player hasn't been set - if( units[i] > 0 && winningPlayer == player_t::NUM_INVALID ) - { - winningPlayer = (player_t)i; - } - // Otherwise, if there are units in this Player and the winning Player HAS been set - else if ( units[i] > 0 ) - { - // Set back to invalid and break out of the loop - winningPlayer = player_t::NUM_INVALID; - break; - } - } - - return winningPlayer; -} - -// Check if any of the units can move -bool CTTRTSGame::UnitsCanMove() const -{ - for( const SOrderUnitPair& pair: m_OrderUnitPairs ) - { - uvector2 pos = pair.unit.GetPos(); - - // Assume if unit is adjacent to any valid tile, then it can move there - if( VerifyPosIsValidMovement(pos + vector2(1, 0) ) == 0 - || VerifyPosIsValidMovement(pos + vector2(0, 1)) == 0 - || VerifyPosIsValidMovement(pos + vector2(-1, 0)) == 0 - || VerifyPosIsValidMovement(pos + vector2(0, -1)) == 0 ) - { - return true; - } - } - - return false; -} - -// Check if the game is over -bool CTTRTSGame::GameOver() const -{ - return ( (GetWinningPlayer() != player_t::NUM_INVALID ) // We have a winning player - || GetNumUnits() == 0 - || !UnitsCanMove() ); // OR we have no units -} \ No newline at end of file diff --git a/source/ttrts/game.h b/source/ttrts/game.h deleted file mode 100644 index 1401b33..0000000 --- a/source/ttrts/game.h +++ /dev/null @@ -1,107 +0,0 @@ -#ifndef _GAME_H_ -#define _GAME_H_ - -#include "unit.h" -#include "gametypes.h" -#include "order.h" -#include "orderunitpair.h" - -// Full TTRTS Game class -// Stores information about the game -// Can convert from a string or to a string -class CTTRTSGame -{ -public: - - // Constructors - CTTRTSGame( ucoord_t c, ucoord_t r ); - CTTRTSGame(CTTRTSGame&& game); - - // move asignment operator - CTTRTSGame& operator=(CTTRTSGame&& game); - - // Simulate and progress to the next turn - // Returns non-zero if simulation failed - int SimulateToNextTurn(); - - // Check for winning player, returns invalid for no win state reached - // Note: this function will return invalid if a draw was reached - // do not rely on this to test for end state - player_t GetWinningPlayer() const; - - // Check if the game is over - bool GameOver() const; - - // Check if any of the units can move - bool UnitsCanMove() const; - - // Issue orders to the game, returns non-zero if orders are incorrect - int IssueOrders( player_t player, const std::string& orders ); - int IssueOrders( player_t player, const COrderVector& orders ); - int IssueOrder( player_t player, const SOrder & order ); - - // Add a units to the game, nonzero return value indicates error - int AddUnit( CUnit&& unit ); - int AddUnits( CUnitVector&& units ); - - // Get the number of units - inline unsigned int GetNumUnits() const { return m_OrderUnitPairs.size(); } - - // Get unit and orderby index as above (not unit ID) - inline const CUnit& GetUnitByIndex( unsigned int i ) const { return m_OrderUnitPairs[i].unit; } - inline const SOrder & GetOrdersByIndex( unsigned int i ) const { return m_OrderUnitPairs[i].order; } - - // Get a unit by it's ID - const CUnit& GetUnitByIDConst( unit_id_t id ) const; - const SOrder & GetOrderByIDConst( unit_id_t id ) const; - - inline const OrderUnitPairVector& GetOrderUnitPairs() const { return m_OrderUnitPairs; } - - // Get dimensions - inline const uvector2& GetDimensions() const { return dimensions; } - - // Set the game name - // NOTE: Names with spaces not allowed - inline std::string SetName( const std::string& in ) { return (name = in); } - inline std::string GetName() const { return name; } - - // Set the turn of the game - inline int SetTurn( int in ) { return (turn = in); } - inline int GetTurn() const { return turn; } - - // Get a vector of the players in the current game - std::vector GetPlayers() const; - - // Get the vector of wall positions - inline std::vector GetWalls() const { return m_walls; } - - // Add an invalid position - inline void AddWall(uvector2 vec) { m_walls.push_back(vec); } - -private: - - // Check for a pass through - static bool CheckForPassThrough( const CUnit& one, const CUnit& two ); - - // Verify any order or position - non-zero is error - int VerifyOrder( player_t player, const SOrder & order ) const; - int VerifyPosIsValidMovement(uvector2 vec) const; - - // Get a units new position after an order - uvector2 GetNewPosition( const SOrderUnitPair & pair ) const; - - // Kill all units in list - void KillAll( std::vector< unit_id_t >& vec ); - - // Get unit by unit ID - CUnit& GetUnitByID( unit_id_t id ); - - std::string name; // Game Name - unsigned int turn; // Int to store the current turn - uvector2 dimensions; // Dimensions of the game - OrderUnitPairVector m_OrderUnitPairs; // Vector to store all units and orders - std::vector m_walls; // Vector of wall positions -}; - - -#endif //_GAME_H_ diff --git a/source/ttrts/gametypes.h b/source/ttrts/gametypes.h deleted file mode 100644 index b01318d..0000000 --- a/source/ttrts/gametypes.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef _GAME_TYPES_H_ -#define _GAME_TYPES_H_ - -#include // std::numeric_limits -#include "stdlib.h" // for size_t - -// Type for a Player IDs -enum class player_t : char -{ - Red = 0, - Green, - Yellow, - Blue, - NUM_INVALID -}; - -// Type for unit IDs -typedef unsigned short unit_id_t; -static const unit_id_t unit_id_invalid = std::numeric_limits::max(); - -// Typedef for unit visual representations -typedef char unitvis_c; -static const unitvis_c unitvis_invalid = std::numeric_limits::max(); - -// Coordinate types -typedef short coord_t; -static const coord_t coord_invalid = std::numeric_limits::max(); - -typedef unsigned short ucoord_t; -static const ucoord_t ucoord_invalid = std::numeric_limits::max(); - -// Direction representation -enum class dir_c : char -{ - N = 'N', - S = 'S', - E = 'E', - W = 'W' -}; - -// Helper function for count of an array -template -constexpr size_t _countof(T (&)[N]) { return N; } - -#endif //_GAME_TYPES_H_ \ No newline at end of file diff --git a/source/ttrts/order.h b/source/ttrts/order.h deleted file mode 100644 index 1ad995a..0000000 --- a/source/ttrts/order.h +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef _ORDERS_H_ -#define _ORDERS_H_ - -#include -#include - -#include "gametypes.h" - -#define ORDER_FORMATTER "ORDER:%c id:%u" - -// Type for all orders ( as a char ) -enum class command_c : char -{ - F = 'F', // Move forward one square - L = 'L', // Turn left - R = 'R', // Turn right - A = 'A', // Attack forwards until a unit or edge of the arena is hit - NUM_INVALID -}; - -// Container for an order -struct SOrder -{ - // Base constructor makes invalid order - SOrder() - : unit ( unit_id_invalid ) - , command( command_c::NUM_INVALID ) - {} - - // Unit order is for - unit_id_t unit; - - // Order command issued - command_c command; - - // Basic operators - inline bool operator==( const SOrder & rhs ) const; - inline bool operator!=( const SOrder & rhs ) const { return !(*this==rhs); } -}; - -// Simple == operator -inline bool SOrder::operator== ( const SOrder & rhs ) const -{ - return ( unit == rhs.unit ) && ( command == rhs.command); -} - -// Typedef a vector of orders -typedef std::vector COrderVector; - -#endif //_ORDERS_H_ diff --git a/source/ttrts/orderunitpair.h b/source/ttrts/orderunitpair.h deleted file mode 100644 index 278608c..0000000 --- a/source/ttrts/orderunitpair.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef _TTRTS_ORDERUNITPAIR_H_ -#define _TTRTS_ORDERUNITPAIR_H_ - -#include "order.h" -#include "unit.h" - -#include - -// Type for order and unit pairs -struct SOrderUnitPair -{ - // Straight up move constructor - SOrderUnitPair( SOrderUnitPair && other ) - : unit ( std::move(other.unit) ) - , order ( other.order ) - {} - - // Multi parameter constructor - SOrderUnitPair( CUnit&& u, SOrder o ) - : unit ( std::move(u) ) - , order ( o ) - {} - - // Move assignment operator - inline SOrderUnitPair & operator=( SOrderUnitPair && rhs ) - { - this->unit = std::move(rhs.unit); - this->order = std::move(rhs.order); - return *this; - } - - CUnit unit; // The unit - SOrder order; // Order for this unit from this turn -}; - -// Typedef for a vector of these unit pairs -typedef std::vector OrderUnitPairVector; - -#endif // _TTRTS_ORDERUNITPAIR_H_ \ No newline at end of file diff --git a/source/ttrts/unit.cpp b/source/ttrts/unit.cpp deleted file mode 100644 index b6708c5..0000000 --- a/source/ttrts/unit.cpp +++ /dev/null @@ -1,217 +0,0 @@ -#include -#include "unit.h" - -#include // for std::map - -namespace -{ - // Helper function for generating unique unit ids during static init - unit_id_t get_unique_unit_id(unit_id_t* set = nullptr) - { - static unit_id_t p = 0; - - // If we have a set value, then set our int - if( set ) - p = *set; - - return p++; - } - - // Map of visual representation of unit V - typedef std::map dir_to_vis_map; - - // Helper function to get the vis map during static init - const dir_to_vis_map& get_vis_map_V() - { - static const dir_to_vis_map sk_visMap = - { - {dir_c::N,'^'}, - {dir_c::E,'>'}, - {dir_c::S,'v'}, - {dir_c::W,'<'}, - }; - - return sk_visMap; - } -} - -// force a reset of the unit ID value -void __forceResetCUnitID() -{ - unit_id_t i = 0; - get_unique_unit_id(&i); -} - -// Get a unit from a visual -CUnit CUnit::GetUnitFromVis( unitvis_c vis ) -{ - CUnit unit; - unit.SetFromVisual(vis); - return unit; -} - -// Plain constructor -CUnit::CUnit() -: unit_id ( get_unique_unit_id() ) -, player_id ( player_t::NUM_INVALID ) -, unit_vis (unitvis_invalid) -, dir ( dir_c::S ) -, pos ( { ucoord_invalid, ucoord_invalid } ) -{ - UpdateMyVisual(); -} - -// Move constructor -CUnit::CUnit(CUnit&& unit) -: unit_id ( std::move(unit.unit_id) ) -, player_id ( std::move(unit.player_id) ) -, unit_vis ( std::move(unit.unit_vis) ) -, dir ( std::move(unit.dir) ) -, pos ( std::move(unit.pos) ) -{ - UpdateMyVisual(); -} - - -// Move asignment operator -CUnit& CUnit::operator=(CUnit&& unit) -{ - unit_id = std::move(unit.unit_id) ; - player_id = std::move(unit.player_id) ; - unit_vis = std::move(unit.unit_vis) ; - dir = std::move(unit.dir) ; - pos = std::move(unit.pos) ; - return *this; -} - -// Equals operator -bool CUnit::operator==(const CUnit& rhs) -{ - return (unit_id == rhs.unit_id) - && (player_id == rhs.player_id) - && (unit_vis == rhs.unit_vis) - && (dir == rhs.dir) - && (pos == rhs.pos); -} - -// Update the visual representation of the unit -unitvis_c CUnit::UpdateMyVisual() -{ - // Start at invalid - SetVisual(unitvis_invalid); - - dir_to_vis_map::const_iterator it = get_vis_map_V().find(dir); - - // If found set to new vis - if( it != get_vis_map_V().end() ) - SetVisual(it->second); - - return GetVisual(); -} - -// Set the unit from visual -bool CUnit::SetFromVisual(const unitvis_c &vis) -{ - dir_to_vis_map::const_iterator it; - - for( it = get_vis_map_V().begin(); it != get_vis_map_V().end(); it++ ) - { - if( it->second == vis ) - { - dir = it->first; - UpdateMyVisual(); - return true; - } - } - - // No matching direction to visual - return false; -} - -// Turn unit left -dir_c CUnit::TurnLeft() -{ - switch( dir ) - { - case dir_c::N: - dir = dir_c::W; - break; - - case dir_c::E: - dir = dir_c::N; - break; - - case dir_c::S: - dir = dir_c::E; - break; - - case dir_c::W: - dir = dir_c::S; - break; - } - - UpdateMyVisual(); - - return GetDir(); -} - -// Turn unit right -dir_c CUnit::TurnRight() -{ - switch( dir ) - { - case dir_c::N: - dir = dir_c::E; - break; - - case dir_c::E: - dir = dir_c::S; - break; - - case dir_c::S: - dir = dir_c::W; - break; - - case dir_c::W: - dir = dir_c::N; - break; - } - - UpdateMyVisual(); - - return GetDir(); -} - -// Turn unit around -dir_c CUnit::TurnAround() -{ - switch( dir ) - { - case dir_c::N: - dir = dir_c::S; - break; - - case dir_c::E: - dir = dir_c::W; - break; - - case dir_c::S: - dir = dir_c::N; - break; - - case dir_c::W: - dir = dir_c::E; - break; - } - - UpdateMyVisual(); - - return GetDir(); -} - -// Get the co-ordinate infront of the unit -uvector2 CUnit::GetInFront() const -{ - vector2 delta = vecFromDir(dir); - return pos + delta; -} diff --git a/source/ttrts/unit.h b/source/ttrts/unit.h deleted file mode 100644 index 7f6e77e..0000000 --- a/source/ttrts/unit.h +++ /dev/null @@ -1,94 +0,0 @@ -#ifndef _UNIT_H_ -#define _UNIT_H_ - -#include -#include - -#include "gametypes.h" -#include "vector2.h" - -// force a reset of the unit ID value -void __forceResetCUnitID(); - -// Base unit type -class CUnit -{ -public: - - // Factory function for creating units from a visual - static CUnit GetUnitFromVis( unitvis_c vis ); - - // Constructor - CUnit(); - - // Move constructor and move assignment. CUnit cannot be copied - CUnit(CUnit&& unit); - CUnit& operator=(CUnit&& unit); - - bool operator==(const CUnit& rhs); - bool operator!=(const CUnit& rhs) { return !(*this == rhs); } - - // Getters for all the members - inline const unit_id_t& GetID() const { return unit_id; } - inline const player_t & GetPlayer() const { return player_id; } - inline const unitvis_c & GetVisual() const { return unit_vis; } - inline const dir_c & GetDir() const { return dir; } - inline const uvector2& GetPos() const { return pos; } - - // Set - inline player_t SetPlayer(const player_t &v) { return (player_id = v); } - inline unitvis_c SetVisual(const unitvis_c &v) { return (unit_vis = v); } - inline dir_c SetDir(const dir_c &v) { return (dir = v); } - inline void SetPos(const uvector2 &v) { pos = v; } - - // Get the co-ordinate in front of the unit - uvector2 GetInFront() const; - - // Check unit is valid - inline bool Valid() const; - - // Set a unit based solely on it's visual - bool SetFromVisual(const unitvis_c &vis); - - // Orientation methods - dir_c TurnLeft(); - dir_c TurnRight(); - dir_c TurnAround(); - - // Force set an ID - inline void ForceSetID( unit_id_t id ) { unit_id = id; } - -private: - - // Update my visual must be called when setting direction - unitvis_c UpdateMyVisual(); - - // Unit ID - unit_id_t unit_id; - - // Visual - unitvis_c unit_vis; - - // Player ID - player_t player_id; - - // Direction - dir_c dir; - - // Position - uvector2 pos; -}; - -// Typedef for a vector of units -typedef std::vector< CUnit > CUnitVector; -typedef std::vector< unit_id_t > CUnitIDVector; - -// Simple validation -inline bool CUnit::Valid() const -{ - return (unit_id != unit_id_invalid ) - && (player_id != player_t::NUM_INVALID ) - && (unit_vis != unitvis_invalid); -} - -#endif //_UNIT_H_ diff --git a/source/ttrts/vector2.h b/source/ttrts/vector2.h deleted file mode 100644 index 1cd2e34..0000000 --- a/source/ttrts/vector2.h +++ /dev/null @@ -1,84 +0,0 @@ -#ifndef _VECTOR2_H_ -#define _VECTOR2_H_ - -#include "gametypes.h" - -struct uvector2; - -struct vector2 -{ - vector2() : x (0), y (0) {} - vector2( coord_t _x, coord_t _y ) - : x(_x) - , y(_y) - {} - - coord_t x; - coord_t y; - - inline vector2 operator-() const { return { (coord_t)-x, (coord_t)-y }; } - - inline operator uvector2() const; - - // vec - inline vector2 operator+(const vector2& rhs) const { return { (coord_t)(rhs.x + x) , (coord_t)(rhs.y + y) }; } - inline vector2 operator-(const vector2& rhs) const { return *this + (-rhs); } - - inline const vector2& operator+=(const vector2& rhs) { *this = *this+rhs; return *this; } - inline const vector2& operator-=(const vector2& rhs) { return *this+=(-rhs); } - - inline bool operator==(const vector2& rhs) const { return ( rhs.x == x) && ( rhs.y == y); } - inline bool operator!=(const vector2& rhs) const { return !(*this==rhs); } -}; - -struct uvector2 -{ - uvector2() : x (0), y (0) {} - uvector2( ucoord_t _x, ucoord_t _y ) - : x(_x) - , y(_y) - {} - - ucoord_t x; - ucoord_t y; - - // Implicit conversion to vector 2 if needed - inline operator vector2() const { return { (coord_t)x, (coord_t)y }; } - - inline uvector2 operator-() const { return { (ucoord_t)-x, (ucoord_t)-y }; } - - // uvec - inline uvector2 operator+(const uvector2& rhs) const { return { (ucoord_t)(rhs.x + x) , (ucoord_t)(rhs.y + y) }; } - inline uvector2 operator-(const uvector2& rhs) const { return *this + (-rhs); } - - inline const uvector2& operator+=(const uvector2& rhs) { *this = *this+rhs; return *this; } - inline const uvector2& operator-=(const uvector2& rhs) { return *this+=(-rhs); } - - inline bool operator==(const uvector2& rhs) const { return ( rhs.x == x) && ( rhs.y == y); } - inline bool operator!=(const uvector2& rhs) const { return !(*this==rhs); } -}; - -inline vector2::operator uvector2() const { return { (ucoord_t)x, (ucoord_t)y }; } - -inline vector2 vecFromDir( dir_c dir ) -{ - switch( dir ) - { - case dir_c::N: - return { 0,1 }; - - case dir_c::E: - return { 1,0 }; - - case dir_c::S: - return { 0,-1 }; - - case dir_c::W: - return { -1,0 }; - - default: - return { 0,0 }; - } -} - -#endif //_VECTOR2_H_ diff --git a/stylesheets/core.css b/stylesheets/core.css new file mode 100644 index 0000000..7aaec46 --- /dev/null +++ b/stylesheets/core.css @@ -0,0 +1,3 @@ +@import url("screen.css"); +@import url("non-screen.css") handheld; +@import url("non-screen.css") only screen and (max-device-width:640px); \ No newline at end of file diff --git a/stylesheets/mobile.css b/stylesheets/mobile.css new file mode 100644 index 0000000..c860c09 --- /dev/null +++ b/stylesheets/mobile.css @@ -0,0 +1,510 @@ +/* Generated by Font Squirrel (http://www.fontsquirrel.com) on February 9, 2012 */ + + +@font-face { + font-family: 'Open Sans'; + src: url('../fonts/opensans-regular-webfont.eot'); + src: url('../fonts/opensans-regular-webfont.eot?#iefix') format('embedded-opentype'), + url('../fonts/opensans-regular-webfont.woff') format('woff'), + url('../fonts/opensans-regular-webfont.ttf') format('truetype'), + url('../fonts/opensans-regular-webfont.svg#OpenSansRegular') format('svg'); + font-weight: normal; + font-style: normal; +} + +@font-face { + font-family: 'Open Sans'; + src: url('../fonts/opensans-italic-webfont.eot'); + src: url('../fonts/opensans-italic-webfont.eot?#iefix') format('embedded-opentype'), + url('../fonts/opensans-italic-webfont.woff') format('woff'), + url('../fonts/opensans-italic-webfont.ttf') format('truetype'), + url('../fonts/opensans-italic-webfont.svg#OpenSansItalic') format('svg'); + font-weight: normal; + font-style: italic; +} + +@font-face { + font-family: 'Open Sans'; + src: url('../fonts/opensans-bold-webfont.eot'); + src: url('../fonts/opensans-bold-webfont.eot?#iefix') format('embedded-opentype'), + url('../fonts/opensans-bold-webfont.woff') format('woff'), + url('../fonts/opensans-bold-webfont.ttf') format('truetype'), + url('../fonts/opensans-bold-webfont.svg#OpenSansBold') format('svg'); + font-weight: bold; + font-style: normal; +} + +@font-face { + font-family: 'Open Sans'; + src: url('../fonts/opensans-bolditalic-webfont.eot'); + src: url('../fonts/opensans-bolditalic-webfont.eot?#iefix') format('embedded-opentype'), + url('../fonts/opensans-bolditalic-webfont.woff') format('woff'), + url('../fonts/opensans-bolditalic-webfont.ttf') format('truetype'), + url('../fonts/opensans-bolditalic-webfont.svg#OpenSansBoldItalic') format('svg'); + font-weight: bold; + font-style: italic; +} + +@font-face { + font-family: 'Open Sans'; + src: url('../fonts/opensans-extrabold-webfont.eot'); + src: url('../fonts/opensans-extrabold-webfont.eot?#iefix') format('embedded-opentype'), + url('../fonts/opensans-extrabold-webfont.woff') format('woff'), + url('../fonts/opensans-extrabold-webfont.ttf') format('truetype'), + url('../fonts/opensans-extrabold-webfont.svg#OpenSansExtrabold') format('svg'); + font-weight: bolder; + font-style: normal; +} + + +/* http://meyerweb.com/eric/tools/css/reset/ + v2.0 | 20110126 + License: none (public domain) +*/ + +html, body, div, span, applet, object, iframe, +h1, h2, h3, h4, h5, h6, p, blockquote, pre, +a, abbr, acronym, address, big, cite, code, +del, dfn, em, img, ins, kbd, q, s, samp, +small, strike, strong, sub, sup, tt, var, +b, u, i, center, +dl, dt, dd, ol, ul, li, +fieldset, form, label, legend, +table, caption, tbody, tfoot, thead, tr, th, td, +article, aside, canvas, details, embed, +figure, figcaption, footer, header, hgroup, +menu, nav, output, ruby, section, summary, +time, mark, audio, video { + margin: 0; + padding: 0; + border: 0; + font-size: 100%; + font: inherit; + vertical-align: baseline; +} +/* HTML5 display-role reset for older browsers */ +article, aside, details, figcaption, figure, +footer, header, hgroup, menu, nav, section { + display: block; +} +body { + line-height: 1; +} +ol, ul { + list-style: none; +} +blockquote, q { + quotes: none; +} +blockquote:before, blockquote:after, +q:before, q:after { + content: ''; + content: none; +} +table { + border-collapse: collapse; + border-spacing: 0; +} + +header, footer, section { + display: block; + position: relative; +} + +/* STYLES */ + +div.shell { + display: block; + width: 640px; + margin: 0 auto; +} + +a#forkme_banner { + display: none; +} + +/* header */ + +header { + position: relative; + z-index: 2; + margin: 0; + max-width: 640px; + top: 51px; +} + +header span.ribbon-inner { + position: relative; + display: block; + background-color: #cd596b; + border: 8px solid #7c334f; + padding: 6px; + z-index: 1; +} + +header span.left-tail, header span.right-tail { + position: relative; + display: block; + width: 19px; + height: 10px; + background: transparent url(../images/ribbon-tail-sprite-2x.png) 0 0 no-repeat; + position: absolute; + bottom: -10px; + z-index: 0; +} + +header span.left-tail { + background-position: 0 0; + left: 0; +} + +header span.right-tail { + background-position: -19px 0; + right: 0; +} + +header h1 { + background-color: #7c334f; + font-size: 2em; + font-weight: bolder; + font-style: normal; + text-transform: uppercase; + color: #ece4d8; + text-align: center; + line-height:1; + padding: 14px 20px 0; +} + +header h2 { + background-color: #7c334f; + font: bold italic .85em/1.5 Georgia, Times, “Times New Roman”, serif; + color: #e69b95; + padding-bottom: 14px; + margin-top: -3px; + text-align: center; +} + +section#downloads { + position: relative; + display: block; + height: 171px; + width: 602px; + padding-bottom: 150px; + margin: 51px auto -250px; + z-index: 1; + background: transparent url(../images/shield.png) center 0 no-repeat; +} + +section#downloads a { + display: none; +} + +span.banner-fix { + background: transparent url(../images/shield-fallback.png) center top no-repeat; + display: block; + height: 31px; + position: absolute; + width: 640px; + top: 20px; + +} + +section#main_content { + z-index: 2; + padding: 20px 40px 0; + min-height:185px; +} + +/* footer */ + +footer { + background: none; + padding-top: 104px; + margin: -94px auto 40px; + max-width:640px; + text-align: center; +} + +footer span.ribbon-outer { + display: block; + position: relative; + border-bottom: 2px solid #bdb6ad; +} + +footer span.ribbon-inner { + position: relative; + display: block; + background-color: #cd596b; + border: 8px solid #7c334f; + padding: 6px; + z-index: 1; +} + +footer p { + font-family: 'Open Sans', sans-serif; + font-weight: bold; + font-size: .6em; + color: #8b786f; +} + +footer a { + color: #cd596b; +} + +footer span.ribbon-inner p { + background-color: #7c334f; + margin: 0; + color: #e69b95; + font: bold italic 22px/1 Georgia, Times, “Times New Roman”, serif; + height: auto; + line-height: 1.1; + padding: 20px 0px 10px; +} + +footer span.ribbon-inner a { + display: block; + position: relative; + bottom: 0; + color: #7eb0d2; + font-family: 'Open Sans', sans-serif; + text-transform: uppercase; + font-style: normal; + font-weight: bolder; + font-size: 38px; + padding-bottom: 10px; +} + +footer span.ribbon-inner a:hover { + color: #7eb0d2; +} + +footer span.left-tail, footer span.right-tail { + position: relative; + display: block; + width: 23px; + height: 126px; + background: transparent url(../images/small-ribbon-tail-sprite-2x.png) 0 0 no-repeat; + position: absolute; + top: -126px; + z-index: 0; +} + +footer span.left-tail { + background-position: 0 0; + left: 0; +} + +footer span.right-tail { + background-position: -23px 0; + right: 0; +} + +footer span.octocat { + background: transparent url(../images/octocat-2x.png) 0 0 no-repeat; + display: block; + width: 60px; + height: 60px; + margin: 20px auto 0;} + +/* content */ + +body { + background: #ece4d8; + font: normal normal 30px/1.5 Georgia, Palatino,” Palatino Linotype”, Times, “Times New Roman”, serif; + color: #544943; + -webkit-font-smoothing: antialiased; +} + +a, a:hover { + color: #417090; +} + +a { + text-decoration: none; +} + +a:hover { + text-decoration: underline; +} + +h1,h2,h3,h4,h5,h6 { + font-family: 'Open Sans', sans-serif; + font-weight: bold; +} + +p { + margin: .7em 0 0; +} + +strong { + font-weight: bold; +} + +em { + font-style: italic; +} + +ol { + margin: .7em 0; + list-style-type: decimal; + padding-left: 1.35em; +} + +ul { + margin: .7em 0; + padding-left: 1.35em; +} + +ul li { + padding-left: 20px; + background: transparent url(../images/chevron-2x.png) left 15px no-repeat; +} + +blockquote { + font-family: 'Open Sans', sans-serif; + margin: 20px 0; + color: #8b786f; + padding-left: 1.35em; + background: transparent url('../images/blockquote-gfx-2x.png') 0 8px no-repeat; +} + +img { + -webkit-box-shadow: 0px 4px 0px #bdb6ad; + -moz-box-shadow: 0px 4px 0px #bdb6ad; + box-shadow: 0px 4px 0px #bdb6ad; + border: 4px solid #fff6e9; + max-width: 556px; +} + +hr { + border: none; + outline: none; + height: 42px; + background: transparent url('../images/hr-2x.jpg') center center repeat-x; + margin: 0 0 20px; +} + +code { + background: #fff6e9; + font: normal normal .9em/1.7 "Lucida Sans Typewriter", "Lucida Console", Monaco, "Bitstream Vera Sans Mono", monospace; + padding: 0 5px 1px; +} + +pre { + margin: 10px 0 20px; + padding: .7em; + background: #fff6e9; + border-bottom: 4px solid #bdb6ad; + font: normal normal .9em/1.7 "Lucida Sans Typewriter", "Lucida Console", Monaco, "Bitstream Vera Sans Mono", monospace; + overflow: auto; +} + +table { + background: #fff6e9; + display: table; + width: 100%; + border-collapse: separate; + border-bottom: 4px solid #bdb6ad; + margin: 10px 0; +} + +tr { + display: table-row; +} + +th { + display: table-cell; + padding: 2px 10px; + border: solid #ece4d8; + border-width: 0 4px 4px 0; + color: #cd596b; + font-family: 'Open Sans', sans-serif; + font-weight: bold; + font-size: .85em; +} + +td { + display: table-cell; + padding: 0 .7em; + border: solid #ece4d8; + border-width: 0 4px 4px 0; +} + +td:last-child, th:last-child { + border-right: none; +} + +tr:last-child td { + border-bottom: none; +} + +dl { + margin: .7em 0 20px; +} + +dt { + font-family: 'Open Sans', sans-serif; + font-weight: bold; +} + +dd { + padding-left: 1.35em; +} + +dd p:first-child { + margin-top: 0; +} + +/* Content based headers */ + +#main_content > .header-level-1:first-child, +#main_content > .header-level-2:first-child, +#main_content > .header-level-3:first-child, +#main_content > .header-level-4:first-child, +#main_content > .header-level-5:first-child, +#main_content > .header-level-6:first-child { + margin-top: 0; +} + +.header-level-1 { + font-size: 1.85em; + border-bottom: .2em double #d3ccc1; + color: #7c334f; + text-align: center; + font-style: italic; + margin: 1.1em 0 .38em; + line-height: 1.2; + padding-bottom: 10px +} + +.header-level-2 { + font-size: 1.58em; + color: #7c334f; + margin: .95em 0 .5em; + border-bottom: .1em solid #D3CCC1; + line-height: 1.2; + padding-bottom: 10px +} + +.header-level-3 { + margin: 20px 0 10px; + font-size: 1.45em; +} + +.header-level-4 { + margin: .6em 0; + font-size: 1.2em; + color: #cd596b; +} + +.header-level-5 { + margin: .7em 0; + font-size: 1em; + color: #8b786f; +} + +.header-level-6 { + margin: .8em 0; + font-size: .85em; + font-style: italic; +} \ No newline at end of file diff --git a/stylesheets/non-screen.css b/stylesheets/non-screen.css new file mode 100644 index 0000000..eea5ecd --- /dev/null +++ b/stylesheets/non-screen.css @@ -0,0 +1,154 @@ +a#forkme_banner { + display: none; +} + +div.shell { + width: 640px; +} + + +header { + max-width:640px; + margin: 0; + top: 51px; +} + +header span.ribbon-inner { + border: 8px solid #7c334f; + padding: 6px; +} + +header span.left-tail, header span.right-tail { + width: 19px; + height: 10px; + background: transparent url(../images/ribbon-tail-sprite-2x.png) 0 0 no-repeat; + bottom: -10px; +} + +header span.left-tail { + left: 0; +} + +header span.right-tail { + background-position: -19px 0; + right: 0; +} + +header h1 { + font-size: 2em; +} + +section#downloads { + height: 171px; + width: 602px; + margin: 51px auto -250px; + background: transparent url(../images/shield.png) center 0 no-repeat; +} + +section#downloads a { + display: none; +} + +span.banner-fix { + background: transparent url(../images/shield-fallback.png) center top no-repeat; + height: 31px; + width: 640px; + top: 20px; +} + +section#main_content { + padding: 20px 40px 0; +} + +footer { + max-width:640px; + background: none; +} + +footer span.left-tail, footer span.right-tail { + width: 23px; + height: 126px; + background: transparent url(../images/small-ribbon-tail-sprite-2x.png) 0 0 no-repeat; + top: -126px; +} + +footer span.left-tail { + left: 0; +} + +footer span.right-tail { + background-position: -23px 0; + right: 0; +} + +footer p { + font-size: .6em; +} + +footer span.ribbon-inner { + border: 8px solid #7c334f; + padding: 6px; +} + +footer span.ribbon-inner p { + font-size: 22px; + height: auto; + line-height: 1.1; + padding: 20px 0px 10px; +} + +footer span.ribbon-inner a { + font-size: 38px; + display: block; + bottom: 0; + padding-bottom: 10px; +} + +footer span.octocat { + background: transparent url(../images/octocat-2x.png) 0 0 no-repeat; + width: 60px; + height: 60px; + margin: 20px auto 0; +} + +body { + font: normal normal 30px/1.5 Georgia, Palatino,” Palatino Linotype”, Times, “Times New Roman”, serif; +} + +ul li { + padding-left: 20px; + background: transparent url(../images/chevron-2x.png) left 15px no-repeat; +} + +table { + border-bottom: 4px solid #bdb6ad; +} + +th { + border-width: 0 4px 4px 0; +} + +td { + border-width: 0 4px 4px 0; +} + +pre { + border-bottom: 4px solid #bdb6ad; +} + +img { + -webkit-box-shadow: 0px 4px 0px #bdb6ad; + -moz-box-shadow: 0px 4px 0px #bdb6ad; + box-shadow: 0px 4px 0px #bdb6ad; + border: 4px solid #fff6e9; + max-width: 556px; +} + +blockquote { + background: transparent url('../images/blockquote-gfx-2x.png') 0 8px no-repeat; +} + +hr { + height: 42px; + background: transparent url('../images/hr-2x.jpg') center center repeat-x; +} \ No newline at end of file diff --git a/stylesheets/print.css b/stylesheets/print.css new file mode 100644 index 0000000..32d9a9d --- /dev/null +++ b/stylesheets/print.css @@ -0,0 +1,34 @@ +* { + background: none !important; + color: #333 !important; +} + +h1,h2,h3,h4,h5,h6 { + color: #7c334f !important; +} + +a { + color: #417090 !important; +} + +#main_content > .header-level-1:first-child, +#main_content > .header-level-2:first-child, +#main_content > .header-level-3:first-child, +#main_content > .header-level-4:first-child, +#main_content > .header-level-5:first-child, +#main_content > .header-level-6:first-child { + margin-top: 10px !important; +} + +#forkme_banner, +#downloads, +.left-tail, +.right-tail +{ +display: none !important; + +} + +.ribbon-inner,.ribbon-outer { + border: 0 !important; +} diff --git a/stylesheets/pygment_trac.css b/stylesheets/pygment_trac.css new file mode 100644 index 0000000..c6a6452 --- /dev/null +++ b/stylesheets/pygment_trac.css @@ -0,0 +1,69 @@ +.highlight { background: #ffffff; } +.highlight .c { color: #999988; font-style: italic } /* Comment */ +.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */ +.highlight .k { font-weight: bold } /* Keyword */ +.highlight .o { font-weight: bold } /* Operator */ +.highlight .cm { color: #999988; font-style: italic } /* Comment.Multiline */ +.highlight .cp { color: #999999; font-weight: bold } /* Comment.Preproc */ +.highlight .c1 { color: #999988; font-style: italic } /* Comment.Single */ +.highlight .cs { color: #999999; font-weight: bold; font-style: italic } /* Comment.Special */ +.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ +.highlight .gd .x { color: #000000; background-color: #ffaaaa } /* Generic.Deleted.Specific */ +.highlight .ge { font-style: italic } /* Generic.Emph */ +.highlight .gr { color: #aa0000 } /* Generic.Error */ +.highlight .gh { color: #999999 } /* Generic.Heading */ +.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ +.highlight .gi .x { color: #000000; background-color: #aaffaa } /* Generic.Inserted.Specific */ +.highlight .go { color: #888888 } /* Generic.Output */ +.highlight .gp { color: #555555 } /* Generic.Prompt */ +.highlight .gs { font-weight: bold } /* Generic.Strong */ +.highlight .gu { color: #800080; font-weight: bold; } /* Generic.Subheading */ +.highlight .gt { color: #aa0000 } /* Generic.Traceback */ +.highlight .kc { font-weight: bold } /* Keyword.Constant */ +.highlight .kd { font-weight: bold } /* Keyword.Declaration */ +.highlight .kn { font-weight: bold } /* Keyword.Namespace */ +.highlight .kp { font-weight: bold } /* Keyword.Pseudo */ +.highlight .kr { font-weight: bold } /* Keyword.Reserved */ +.highlight .kt { color: #445588; font-weight: bold } /* Keyword.Type */ +.highlight .m { color: #009999 } /* Literal.Number */ +.highlight .s { color: #d14 } /* Literal.String */ +.highlight .na { color: #008080 } /* Name.Attribute */ +.highlight .nb { color: #0086B3 } /* Name.Builtin */ +.highlight .nc { color: #445588; font-weight: bold } /* Name.Class */ +.highlight .no { color: #008080 } /* Name.Constant */ +.highlight .ni { color: #800080 } /* Name.Entity */ +.highlight .ne { color: #990000; font-weight: bold } /* Name.Exception */ +.highlight .nf { color: #990000; font-weight: bold } /* Name.Function */ +.highlight .nn { color: #555555 } /* Name.Namespace */ +.highlight .nt { color: #000080 } /* Name.Tag */ +.highlight .nv { color: #008080 } /* Name.Variable */ +.highlight .ow { font-weight: bold } /* Operator.Word */ +.highlight .w { color: #bbbbbb } /* Text.Whitespace */ +.highlight .mf { color: #009999 } /* Literal.Number.Float */ +.highlight .mh { color: #009999 } /* Literal.Number.Hex */ +.highlight .mi { color: #009999 } /* Literal.Number.Integer */ +.highlight .mo { color: #009999 } /* Literal.Number.Oct */ +.highlight .sb { color: #d14 } /* Literal.String.Backtick */ +.highlight .sc { color: #d14 } /* Literal.String.Char */ +.highlight .sd { color: #d14 } /* Literal.String.Doc */ +.highlight .s2 { color: #d14 } /* Literal.String.Double */ +.highlight .se { color: #d14 } /* Literal.String.Escape */ +.highlight .sh { color: #d14 } /* Literal.String.Heredoc */ +.highlight .si { color: #d14 } /* Literal.String.Interpol */ +.highlight .sx { color: #d14 } /* Literal.String.Other */ +.highlight .sr { color: #009926 } /* Literal.String.Regex */ +.highlight .s1 { color: #d14 } /* Literal.String.Single */ +.highlight .ss { color: #990073 } /* Literal.String.Symbol */ +.highlight .bp { color: #999999 } /* Name.Builtin.Pseudo */ +.highlight .vc { color: #008080 } /* Name.Variable.Class */ +.highlight .vg { color: #008080 } /* Name.Variable.Global */ +.highlight .vi { color: #008080 } /* Name.Variable.Instance */ +.highlight .il { color: #009999 } /* Literal.Number.Integer.Long */ + +.type-csharp .highlight .k { color: #0000FF } +.type-csharp .highlight .kt { color: #0000FF } +.type-csharp .highlight .nf { color: #000000; font-weight: normal } +.type-csharp .highlight .nc { color: #2B91AF } +.type-csharp .highlight .nn { color: #000000 } +.type-csharp .highlight .s { color: #A31515 } +.type-csharp .highlight .sc { color: #A31515 } diff --git a/stylesheets/screen.css b/stylesheets/screen.css new file mode 100644 index 0000000..ba63020 --- /dev/null +++ b/stylesheets/screen.css @@ -0,0 +1,569 @@ +/* Generated by Font Squirrel (http://www.fontsquirrel.com) on February 9, 2012 */ + + +@font-face { + font-family: 'Open Sans'; + src: url('../fonts/opensans-regular-webfont.eot'); + src: url('../fonts/opensans-regular-webfont.eot?#iefix') format('embedded-opentype'), + url('../fonts/opensans-regular-webfont.woff') format('woff'), + url('../fonts/opensans-regular-webfont.ttf') format('truetype'), + url('../fonts/opensans-regular-webfont.svg#OpenSansRegular') format('svg'); + font-weight: normal; + font-style: normal; +} + +@font-face { + font-family: 'Open Sans'; + src: url('../fonts/opensans-italic-webfont.eot'); + src: url('../fonts/opensans-italic-webfont.eot?#iefix') format('embedded-opentype'), + url('../fonts/opensans-italic-webfont.woff') format('woff'), + url('../fonts/opensans-italic-webfont.ttf') format('truetype'), + url('../fonts/opensans-italic-webfont.svg#OpenSansItalic') format('svg'); + font-weight: normal; + font-style: italic; +} + +@font-face { + font-family: 'Open Sans'; + src: url('../fonts/opensans-bold-webfont.eot'); + src: url('../fonts/opensans-bold-webfont.eot?#iefix') format('embedded-opentype'), + url('../fonts/opensans-bold-webfont.woff') format('woff'), + url('../fonts/opensans-bold-webfont.ttf') format('truetype'), + url('../fonts/opensans-bold-webfont.svg#OpenSansBold') format('svg'); + font-weight: bold; + font-style: normal; +} + +@font-face { + font-family: 'Open Sans'; + src: url('../fonts/opensans-bolditalic-webfont.eot'); + src: url('../fonts/opensans-bolditalic-webfont.eot?#iefix') format('embedded-opentype'), + url('../fonts/opensans-bolditalic-webfont.woff') format('woff'), + url('../fonts/opensans-bolditalic-webfont.ttf') format('truetype'), + url('../fonts/opensans-bolditalic-webfont.svg#OpenSansBoldItalic') format('svg'); + font-weight: bold; + font-style: italic; +} + +@font-face { + font-family: 'Open Sans'; + src: url('../fonts/opensans-extrabold-webfont.eot'); + src: url('../fonts/opensans-extrabold-webfont.eot?#iefix') format('embedded-opentype'), + url('../fonts/opensans-extrabold-webfont.woff') format('woff'), + url('../fonts/opensans-extrabold-webfont.ttf') format('truetype'), + url('../fonts/opensans-extrabold-webfont.svg#OpenSansExtrabold') format('svg'); + font-weight: 800; + font-style: normal; +} + +/* http://meyerweb.com/eric/tools/css/reset/ + v2.0 | 20110126 + License: none (public domain) +*/ + +html, body, div, span, applet, object, iframe, +h1, h2, h3, h4, h5, h6, p, blockquote, pre, +a, abbr, acronym, address, big, cite, code, +del, dfn, em, img, ins, kbd, q, s, samp, +small, strike, strong, sub, sup, tt, var, +b, u, i, center, +dl, dt, dd, ol, ul, li, +fieldset, form, label, legend, +table, caption, tbody, tfoot, thead, tr, th, td, +article, aside, canvas, details, embed, +figure, figcaption, footer, header, hgroup, +menu, nav, output, ruby, section, summary, +time, mark, audio, video { + margin: 0; + padding: 0; + border: 0; + font-size: 100%; + font: inherit; + vertical-align: baseline; +} +/* HTML5 display-role reset for older browsers */ +article, aside, details, figcaption, figure, +footer, header, hgroup, menu, nav, section { + display: block; +} +body { + line-height: 1; +} +ol, ul { + list-style: none; +} +blockquote, q { + quotes: none; +} +blockquote:before, blockquote:after, +q:before, q:after { + content: ''; + content: none; +} +table { + border-collapse: collapse; + border-spacing: 0; +} + +header, footer, section { + display: block; + position: relative; +} + +/* STYLES */ + +div.shell { + display: block; + width: 670px; + margin: 0 auto; +} + +a#forkme_banner { + position: absolute; + top: 0; + left: 0; + width: 138px; + height: 138px; + display: block; + background: transparent url(../images/fork-sprite.png) 0 0 no-repeat; + text-indent: -9000px; + z-index: 3; +} + +a#forkme_banner:hover { + background-position: 0 -138px; +} + +/* header */ + +header { + position: relative; + z-index: 2; + margin: 0 auto; + max-width: 600px; + top: 38px; +} + +header span.ribbon-inner { + position: relative; + display: block; + background-color: #cd596b; + border: 4px solid #7c334f; + padding: 2px; + z-index: 1; +} + +header span.left-tail, header span.right-tail { + position: relative; + display: block; + width: 56px; + height: 105px; + background: transparent url(../images/ribbon-tail-sprite.png) 0 0 no-repeat; + position: absolute; + bottom: -37px; + z-index: 0; +} + +header span.left-tail { + background-position: 0 0; + left: -31px; +} + +header span.right-tail { + background-position: -56px 0; + right: -31px; +} + +header h1 { + background-color: #7c334f; + font-size: 2.5em; + font-weight: 800; + font-style: normal; + text-transform: uppercase; + color: #ece4d8; + text-align: center; + line-height:1; + padding: 14px 20px 0; +} + +header h2 { + background-color: #7c334f; + font: bold italic .85em/1.5 Georgia, Times, “Times New Roman”, serif; + color: #e69b95; + padding-bottom: 14px; + margin-top: -3px; + text-align: center; +} + +section#downloads, +div#no-downloads { + position: relative; + display: block; + height: 197px; + width: 550px; + padding-bottom: 150px; + margin: -80px auto -150px; + z-index: 1; + background: transparent url(../images/bg-ramp.jpg) center 171px no-repeat; +} + +div#no-downloads span.inner { + display: block; + position: relative; + height: 197px; + width: 550px; + background: transparent url(../images/download-sprite.png) 0 0 no-repeat; +} + +section#downloads a { + display: block; + position: relative; + height: 67px; + width: 275px; + padding-top: 130px; + background: transparent url(../images/download-sprite.png) 0 0 no-repeat; + text-align: center; + line-height: 1; + color: #fff; + font-family: 'Open Sans', Myriad, Calibri, sans-serif; + font-weight: 800; + font-size: 1.3em; +} + +section#downloads a:hover { + text-decoration: none; +} + +section#downloads a em { + font: bold italic 12px/1 Georgia, Times, “Times New Roman”, serif; + color: #83b7da; + display: block; +} + +section#downloads a.zip { + float: left; + background-position: 0 0; +} + +section#downloads a.tgz { + float: right; + background-position: -275px 0; +} + +section#downloads a.zip:hover { + background-position: 0 -197px; +} + +section#downloads a.tgz:hover { + background-position: -275px -197px; +} + +span.banner-fix { + background: transparent url(../images/download-fallback-bg.png) center top no-repeat; + display: block; + height: 19px; + position: absolute; + width: 670px; + top: 19px; +} + +section#main_content { + z-index: 2; + padding: 20px 82px 0; + min-height:185px; +} + +/* footer */ + +footer { + background: transparent url(../images/footer-ramp.jpg) center -1px no-repeat; + padding-top: 104px; + margin: -94px auto 40px; + max-width: 560px; + text-align: center; +} + +footer span.ribbon-outer { + display: block; + position: relative; + border-bottom: 2px solid #bdb6ad; +} + +footer span.ribbon-inner { + position: relative; + display: block; + background-color: #cd596b; + border: 2px solid #7c334f; + padding: 1px; + z-index: 1; +} + +footer p { + font-family: 'Open Sans', Myriad, Calibri, sans-serif; + font-weight: bold; + font-size: .8em; + color: #8b786f; +} + +footer a { + color: #cd596b; +} + +footer span.ribbon-inner p { + background-color: #7c334f; + margin: 0; + color: #e69b95; + font: bold italic 12px/1 Georgia, Times, “Times New Roman”, serif; + padding-bottom:4px; +} + +footer span.ribbon-inner a { + position: relative; + bottom: -1px; + color: #7eb0d2; + font-family: 'Open Sans', Myriad, Calibri, sans-serif; + text-transform: uppercase; + font-style: normal; + font-weight: 800; + font-size: 1.2em; +} + +footer span.ribbon-inner a:hover { + color: #7eb0d2; +} + +footer span.left-tail, footer span.right-tail { + position: relative; + display: block; + width: 18px; + height: 29px; + background: transparent url(../images/small-ribbon-tail-sprite.png) 0 0 no-repeat; + position: absolute; + bottom: 5px; + z-index: 0; +} + +footer span.left-tail { + background-position: 0 0; + left: -11px; +} + +footer span.right-tail { + background-position: -18px 0; + right: -11px; +} + +footer span.octocat { + background: transparent url(../images/octocat.png) 0 0 no-repeat; + display: block; + width: 30px; + height: 30px; + margin: 0 auto; +} + +/* content */ + +body { + background: #ece4d8; + font: normal normal 15px/1.5 Georgia, Palatino,” Palatino Linotype”, Times, “Times New Roman”, serif; + color: #544943; + -webkit-font-smoothing: antialiased; +} + +a, a:hover { + color: #417090; +} + +a { + text-decoration: none; +} + +a:hover { + text-decoration: underline; +} + +h1,h2,h3,h4,h5,h6 { + font-family: 'Open Sans', Myriad, Calibri, sans-serif; + font-weight: bold; +} + +p { + margin: .7em 0; +} + +strong { + font-weight: bold; +} + +em { + font-style: italic; +} + +ol { + margin: .7em 0; + list-style-type: decimal; + padding-left: 1.35em; +} + +ul { + margin: .7em 0; + padding-left: 1.35em; +} + +ul li { + padding-left: 10px; + background: transparent url(../images/chevron.png) left 6px no-repeat; +} + +blockquote { + font-family: 'Open Sans', Myriad, Calibri, sans-serif; + margin: 20px 0; + color: #8b786f; + padding-left: 1.35em; + background: transparent url('../images/blockquote-gfx.png') 0 4px no-repeat; +} + +img { + -webkit-box-shadow: 0px 2px 0px #bdb6ad; + -moz-box-shadow: 0px 2px 0px #bdb6ad; + box-shadow: 0px 2px 0px #bdb6ad; + border: 2px solid #fff6e9; + max-width: 502px; +} + +hr { + border: none; + outline: none; + height: 18px; + background: transparent url('../images/hr.jpg') center center repeat-x; + margin: 0 0 20px; +} + +code { + background: #fff6e9; + font: normal normal .8em/1.7 "Lucida Sans Typewriter", "Lucida Console", Monaco, "Bitstream Vera Sans Mono", monospace; + padding: 0 5px 1px; +} + +pre { + margin: 10px 0 20px; + padding: .7em; + background: #fff6e9; + border-bottom: 2px solid #bdb6ad; + font: normal normal .9em/1.7 "Lucida Sans Typewriter", "Lucida Console", Monaco, "Bitstream Vera Sans Mono", monospace; + overflow: auto; +} + +pre code { + padding: 0; +} + +table { + background: #fff6e9; + display: table; + width: 100%; + border-collapse: separate; + border-bottom: 2px solid #bdb6ad; + margin: 10px 0; +} + +tr { + display: table-row; +} + +th { + display: table-cell; + padding: 2px 10px; + border: solid #ece4d8; + border-width: 0 2px 2px 0; + color: #cd596b; + font-family: 'Open Sans', Myriad, Calibri, sans-serif; + font-weight: bold; + font-size: .85em; +} + +td { + display: table-cell; + padding: 0 .7em; + border: solid #ece4d8; + border-width: 0 2px 2px 0; +} + +td:last-child, th:last-child { + border-right: none; +} + +tr:last-child td { + border-bottom: none; +} + +dl { + margin: .7em 0 20px; +} + +dt { + font-family: 'Open Sans', Myriad, Calibri, sans-serif; + font-weight: bold; +} + +dd { + padding-left: 1.35em; +} + +dd p:first-child { + margin-top: 0; +} + +/* Content based headers */ + +#main_content > .header-level-1:first-child, +#main_content > .header-level-2:first-child, +#main_content > .header-level-3:first-child, +#main_content > .header-level-4:first-child, +#main_content > .header-level-5:first-child, +#main_content > .header-level-6:first-child { + margin-top: 0; +} + +.header-level-1 { + font-size: 1.85em; + border-bottom: .2em double #d3ccc1; + color: #7c334f; + text-align: center; + font-style: italic; + margin: 1.1em 0 .38em; + line-height: 1.2; + padding-bottom: 10px +} + +.header-level-2 { + font-size: 1.58em; + color: #7c334f; + margin: .95em 0 .5em; + border-bottom: .1em solid #D3CCC1; + line-height: 1.2; + padding-bottom: 10px +} + +.header-level-3 { + margin: 20px 0 10px; + font-size: 1.45em; +} + +.header-level-4 { + margin: .6em 0; + font-size: 1.2em; + color: #cd596b; +} + +.header-level-5 { + margin: .7em 0; + font-size: 1em; + color: #8b786f; +} + +.header-level-6 { + margin: .8em 0; + font-size: .85em; + font-style: italic; +}