This is a trivial turn-based role-playing fighting game, designed to teach C++.
Apologies to Blizzard Entertainment for cribbing (and butchering) their content.
The goal was to make this "bare bones" without a complicated build so people can see for themselves what is involved in the software.
This does require C++11 because of the use of a std::vector<shared_ptr<T>> for memory management.
The included Makefile automatically compiles the program as follows:
- All files matching
src/%.cc(except for the main executable WorldOfTextCraft.cc) are compiled tobuild/\*.o. - The tests, at
tests/%.cc, are compiled to executablestests/%.exe(linked with thebuild/%.ofiles). src/WorldOfTextCraft.ccis compiled to/bin/WorldOfTextCraft.exe.
In order to compile just type make. To delete your compiled stuff, type make clean, or just manually delete the .exe files.
This program can be run using the PHY410/505 Docker image, https://hub.docker.com/r/subsuny/compphys. From this folder, just run ./runDocker.sh ubsuny/compphys:latest (if using WSL+Ubuntu, instead run ./runDocker_wfix.sh ubsuny/compphys:latest to fix a permissions issue). These are the same scripts that we provide in https://github.com/ubsuny/CompPhys.
Remember to do your work inside the mounted folder! Files outside the mounted folder will be deleted upon exiting the container.
For convenience, you might want to add WorldOfTextCraft/bin to your path, so you can access the executable from anywhere:
cd WorldOfTextCraft
export PATH=$PATH:$(readlink -e bin)
# Now you can call WorldOfTextCraft.exe from anywhereTo run the program:
WorldOfTextCraft.exe player_config boss_config boss_scriptHere, we have:
- player_config: player configuration text file
- boss_config : boss configuration text file
- boss_script : the script of moves the boss will execute
For instance:
cd ExampleBattle
WorldOfTextCraft.exe PlayerCharacters.txt Boss.txt BossScript.txtYou can copy-and-paste lines from PlayerScript.txt into the game to run through the example battle. Note: after your first turn, if you hit "enter", you will execute the previous command without having to type anything.
In all configuration files, lines starting with "!" will be ignored (i.e. comments)
-
Player configuration file:
- Contains a list of party members (i.e., the characters you control) and their stats.
- One line per party member, syntax:
type;name;attack_power;defense_power;heal_power; - Example:
! ! Test party configuration: ! Warrior, Rogue, Priest ! Fields are : ! class, name, attack power, defense power, heal power Warrior;William The Warrior;0;3;0; Priest;Poppy The Priest;0;0;8; Rogue;Rachel The Rogue;20;0;0; -
Boss configuration file:
- First line is the description of the battle to be displayed.
- Then one line per boss, syntax:
name;attack_power;heal_power;defense_power;mana;multi_attack - Example:
!Description: William the Warrior, Poppy the Priest, and Rachel the Rogue enter their first dungeon. Alas, their poor friend Bob has been bitten by a zombie and is trying to kill them. Help William, Poppy, and Rachel put Bob out of his misert! ! Non-Player character. Fields are "name", attack power, heal power, defense power, mana, multi attack power Bob The Boss;20;0;0;10;5; -
Boss script:
- One line per action, syntax:
name;action;target_name; - Here, "action" can be "attack", "heal", or "defend".
- "target_name" can be "target" (to target the first of the Player's party) or "all" to attack the entire party at once.
- Example:
! Test battle configuration. Shemp;attack;target; Shemp;attack;all; - One line per action, syntax:
-
Player script:
- Contains a script for player character actions. Note: this is only implemented in
test_battle.cc, notWorldOfTextCraft.cc. - One line per action, syntax:
name;action;target_name - Here, "action" can be "attack", "heal", or "defend"
- "target_name" must refer to a member of the Boss party.
- Example:
! Test battle configuration. Rachel The Rogue;attack;Bob The Boss; William The Warrior;defend;Bob The Boss; Poppy The Priest;heal;William The Warrior; - Contains a script for player character actions. Note: this is only implemented in
The game is rather simple. Initially there are three player classes, all with 100 hit points, and one Boss class, with 500 hit points. Once a character reaches 0 hit points, it dies. All characters have a common base C++ class "Character", and then override the functionality in that base C++ class to be player-class-specific. Each class only has one meaningful action:
- Rogue: can use "attack", which reduces the hit points of a target by 20.
- Warrior: can use "defend", which forces the target to attack the Warrior. They have a defense mitigation modifier ("defense power") that reduces the hit points lost upon an attack. The final damage is "attack_power - defense_power".
- Priest: can use "heal", which increases the hit points of a target by 20. Starts with 100 mana.
- Boss: can cast any spell, and also has a special
multi_attack, where it attacks the entire party with another statmulti_attack_power. This should be less than the attack power.
You can adjust the game mechanics to add player classes of your own!
In the Lich King scenario, you fight the boss Arthas (the "Lich King" bit is just for flavor, it behaves more or less the same as Bob The Boss from the example). The configuration files are located at WorldOfTextCraft/LichKing.
To run the scenario, make sure WorldOfTextCraft/bin is in your path, and then execute:
cd LichKing
WorldOfTextCraft.exe PlayerCharacters.txt Arthas.txt ArthasAttacks.txtYou will be prompted as follows:
reading PC configuration
Added character: Fordring ( Warrior): HP= 100, mana = 0, no target
Added character: Nakha ( Priest): HP= 100, mana = 100, no target
Added character: Mograine ( Rogue): HP= 100, mana = 0, no target
reading NPC configuration
Input boss: Arthas ( Boss): HP= 500, mana = 0, no target
reading NPC action script
|--------------------------------------------|
|--------------------------------------------|
|--------------------------------------------|
|--------------------------------------------|
| __ __ _ _ |
| / / /\ \ \___ _ __| | __| | |
| \ \/ \/ / _ \| '__| |/ _` | |
| \ /\ / (_) | | | | (_| | |
| \/ \/ \___/|_| |_|\__,_| |
| |
| __ |
| ___ / _| |
| / _ \| |_ |
| | (_) | _| |
| \___/|_| |
| |
| _____ _ ___ __ _ |
|/__ \_____ _| |_ / __\ __ __ _ / _| |_ |
| / /\/ _ \ \/ / __|/ / | '__/ _` | |_| __||
| / / | __/> <| |_/ /__| | | (_| | _| |_ |
| \/ \___/_/\_\\__\____/_| \__,_|_| \__||
| |
|--------------------------------------------|
|--------------------------------------------|
|--------------------------------------------|
Welcome brave traveler...
You venture forth from your stronghold in Azeroth to the icy continent of Northrend, accompanied only by your fellow adventurers and your courage. You have tracked Arthas Menethil to his Frozen Throne in the plagued wastelands of Icecrown. Once a brave champion of Lordaeron, Arthas was corrupted by evil and his soul subsumed by the shaman Ner'zhul upon taking the cursed Runeblade, Frostmourne, forming the character known as the Lich King, threatening all life in Azeroth to become mindless undead slaves of the Burning Legion. The Knights of the Ebon Blade and the Argent Crusade have now formed the Ashen Verdict, and tasked you to destroy the Lich King and end his undead plague upon Azeroth. As you reach the Frozen Throne, the Lich King's seat, you hear a voice in your head. The Lich King whispers "Young heroes, I was once like you. You have come to this place seeking to bring judgement upon the damned. But, be warned. In the end, all that awaits you is death. Only then will you understand, you've been following in my footsteps all along. So come then, you heroes! Come in all your power and glory! For in this final hour, all must serve the one... true... king... Frostmourne HUNGERS....". The battle is joined.
Are you ready to begin? [Y/n]
You can type "n" to exit, or "y" to begin. You will then see a description of the Boss's first attack:
Excellent... let us begin...
----- Action list ----
Arthas will perform action 0 on their target : NO TARGET!
Arthas will perform action 3 on their target : NO TARGET!
------------------------------- Turn : 0-------------------------------
--------------
=== players:
Fordring ( Warrior): HP= 100, mana = 0, no target
Nakha ( Priest): HP= 100, mana = 100, no target
Mograine ( Rogue): HP= 100, mana = 0, no target
=== monsters:
Arthas ( Boss): HP= 500, mana = 0, no target
--------------
Arthas attacks Fordring with attack power 20
Fordring loses 10 hit points after attack 20 and defense 10
Arthas multi-attacks Fordring with attack power 8
Fordring loses 0 hit points after attack 8 and defense 10
Arthas multi-attacks Nakha with attack power 8
Nakha loses 8 hit points after attack 8 and defense 0
Arthas multi-attacks Mograine with attack power 8
Mograine loses 8 hit points after attack 8 and defense 0
Action for Fordring:
You are now at the action prompt. The syntax to perform actions is the same as for the scripting language, so type:
Fordring;defend;Arthas
The game will then print the status of your attack:
Fordring defends against Arthas, defense mitigation 10
You will then have the next player. Enter the next action, and you will again see a printout of the status of your attack:
Action for Nakha:
Nakha;heal;Mograine;
Nakha heals Mograine for 12
Finally you will see your next character. Enter the next action, and another printout will occur:
Mograine;attack;Arthas;
Mograine attacks Arthas with attack power 20
Arthas loses 20 hit points after attack 20 and defense 0
This reaches the end of your turn, so the status is printed again, and it is the boss's turn once more:
------------------------------- Turn : 1-------------------------------
--------------
=== players:
Fordring ( Warrior): HP= 90, mana = 0, target= Arthas
Nakha ( Priest): HP= 92, mana = 90, target= Mograine
Mograine ( Rogue): HP= 100, mana = 0, target= Arthas
=== monsters:
Arthas ( Boss): HP= 480, mana = 0, target= Fordring
--------------
Arthas attacks Fordring with attack power 20
Fordring loses 10 hit points after attack 20 and defense 10
Arthas multi-attacks Fordring with attack power 8
Fordring loses 0 hit points after attack 8 and defense 10
Arthas multi-attacks Nakha with attack power 8
Nakha loses 8 hit points after attack 8 and defense 0
Arthas multi-attacks Mograine with attack power 8
Mograine loses 8 hit points after attack 8 and defense 0
Action for Fordring:
You can then cycle through until your party is victorious (the Boss dies), or fails (all of you die). Note: after your first turn, if you hit "enter", you will execute the previous command without having to type anything. Then the scenario ends. To exit prematurely, simply "control-C" out.
The C++ game will create a log of actions in a JSON format. This will look something like:
{"Turns":[ # Name of the entire structure ("Turns")
{"Turn":0, # This turn number (0)
"Arthas":{"Attacks":[10,0,8,8], # "Name of attacker": "action":[values for action],...
"Defends":[0],
"Heals":[0],
"DamageReceived":[20],
"HealingRecieved":[0]
},
"Fordring":{"Attacks":[0], # "Name of next attacker": "action":[values for action],...
"Defends":[10],
"Heals":[0],
"DamageReceived":[10,0],
"HealingRecieved":[0]
},
"Nakha":{"Attacks":[0], # and so on
"Defends":[0],
"Heals":[8],
"DamageReceived":[8],
"HealingRecieved":[0]
},
"Mograine":{"Attacks":[20],
"Defends":[0],
"Heals":[0],
"DamageReceived":[8],
"HealingRecieved":[8]
}
},
{"Turn":1, # Next turn, and so on.
...
}
]}There is a script readbattle.py that will parse this JSON file and
put the data into a numpy ndarray. If you set the --verbose flag
on the command line, it will also print a table that looks more
columnar like this, with the column headings printed on top:
['Attacks', 'Defends', 'Heals', 'DamageReceived', 'HealingRecieved']
------------ turn : 0 ---------------
==== Arthas : 26, 0, 0, 20, 0,
==== Fordring : 0, 10, 0, 10, 0,
==== Nakha : 0, 0, 8, 8, 0,
==== Mograine : 20, 0, 0, 8, 8,
------------ turn : 1 ---------------
==== Arthas : 26, 0, 0, 20, 0,
==== Fordring : 0, 10, 0, 10, 0,
==== Nakha : 0, 0, 8, 8, 0,
==== Mograine : 20, 0, 0, 8, 8,
...
The numpy array looks like:
[[[26. 0. 0. 20. 0.] <--- Character 0 (in this case, Arthas)
[26. 0. 0. 20. 0.]
[26. 0. 0. 20. 0.]
[26. 0. 0. 20. 0.]
[26. 0. 0. 20. 0.]
[26. 0. 0. 20. 0.]
[26. 0. 0. 20. 0.]
[26. 0. 0. 20. 0.]
[26. 0. 0. 20. 0.]
[26. 0. 0. 20. 0.]
[28. 0. 0. 20. 0.]
[28. 0. 0. 20. 0.]
[28. 0. 0. 20. 0.]
[28. 0. 0. 20. 0.]]
[[ 0. 10. 0. 10. 0.] <--- Character 1 (in this case, Fordring)
[ 0. 10. 0. 10. 0.]
[ 0. 10. 0. 10. 0.]
[ 0. 10. 0. 10. 0.]
[ 0. 10. 0. 10. 0.]
[ 0. 10. 0. 10. 0.]
[ 0. 10. 0. 10. 0.]
[ 0. 10. 0. 10. 0.]
[ 0. 10. 0. 10. 0.]
[ 0. 0. 0. 10. 0.]
[ 0. 0. 0. 0. 0.]
[ 0. 0. 0. 0. 0.]
[ 0. 0. 0. 0. 0.]
[ 0. 0. 0. 0. 0.]]
...
The output array is called npdata and can be used for various analysis purposes.