This commit is contained in:
uid66289 2003-12-23 21:04:20 +00:00
parent 27a1a5d41f
commit 5c890a420f
49 changed files with 963 additions and 325 deletions

View file

@ -1,9 +1,9 @@
Version 0.6: Version 0.6:
* radical storyline changes, this breaks saves from older versions * radical storyline changes, this breaks saves from older versions
* fog of war * fog of war
* support for multiple campaigns
* enemy units do not vanish anymore when enemy leader is killed * enemy units do not vanish anymore when enemy leader is killed
* new scenarios for 'Heir to the Throne' (Konrad's Tale): * new scenarios for 'Heir to the Throne' (Konrad's Tale):
* Isle of the Damned
* Northern Winter * Northern Winter
* The Lost General * The Lost General
* Hasty Alliance * Hasty Alliance
@ -17,6 +17,7 @@ Version 0.6:
* Dwarven Doors * Dwarven Doors
* Mountain Pass * Mountain Pass
* Valley of Death * Valley of Death
* support for multiple campaigns
* new campaign started: 'Hordes of the Undead' * new campaign started: 'Hordes of the Undead'
* multiplayer improvements: * multiplayer improvements:
* show minimap when selecting map for new game * show minimap when selecting map for new game
@ -47,10 +48,12 @@ Version 0.6:
* Elvish Scout * Elvish Scout
* Pikeman * Pikeman
* Dwarvish Steelclad * Dwarvish Steelclad
* undead are now immune to poinson and plague * Konrad now starts as Fighter, which is 1st level unit
* undead are now immune to poison and plague
* reduced movement for Elvish Lord * reduced movement for Elvish Lord
* reduced cost of Mage * reduced cost of Mage
* changed Mage attack to fire based * changed Mage attack to fire based
* 'Mage of Light' has now both cure and illumination
* changed Shaman slowing attack to 3-2 from 4-1, and reduced cost from 21 to 18 * changed Shaman slowing attack to 3-2 from 4-1, and reduced cost from 21 to 18
* changed 'Red Mage' to neutral alignment * changed 'Red Mage' to neutral alignment
* removed 'Elvish Outrider' as evolution from Horseman * removed 'Elvish Outrider' as evolution from Horseman
@ -61,8 +64,8 @@ Version 0.6:
* 'Blood Bat' unit description clarified * 'Blood Bat' unit description clarified
* Halberdier changed to 3rd level unit * Halberdier changed to 3rd level unit
* Spearman now advances to Pikeman * Spearman now advances to Pikeman
* Fire resistance added to 'Red Mage' branch units * Increased fire resistance for 'Red Mage' branch units
* Holy resistance added to Holy units. * Increased holy resistance made higher for Holy units.
* auto-naming (currently elves and humans only) of units and renaming of units * auto-naming (currently elves and humans only) of units and renaming of units
* units now have races defined in cfg-files * units now have races defined in cfg-files
* more and improved unit graphics and animations * more and improved unit graphics and animations
@ -86,6 +89,7 @@ Version 0.6:
* added in support for some special effects: flashing and scrolling/tremors * added in support for some special effects: flashing and scrolling/tremors
* added coding support for displaying different terrain images (particularly useful for villages) at different times of the day * added coding support for displaying different terrain images (particularly useful for villages) at different times of the day
* fixed minor bugs in unit configuration files for Elvish Sharpshooter and Fencer * fixed minor bugs in unit configuration files for Elvish Sharpshooter and Fencer
* fixed problem where 'goto numbers' can overwrite part of the right panel
* footsteps disappear as you walk over them * footsteps disappear as you walk over them
* added engine support for weapons that can reach multiple hexes * added engine support for weapons that can reach multiple hexes
* added some utility macros to WML * added some utility macros to WML
@ -122,6 +126,7 @@ Version 0.6:
* fixed tool tips to work again * fixed tool tips to work again
* fix hitpoint bar problem on MacOSX * fix hitpoint bar problem on MacOSX
* added diagnostic to attack calculations * added diagnostic to attack calculations
* added error logging and correction for combat related syncing errors
* client_type=ai in preferences-file make player join networked multiplayer games as AI player * client_type=ai in preferences-file make player join networked multiplayer games as AI player
* added some comments to code * added some comments to code

2
configure vendored
View file

@ -1337,7 +1337,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
PACKAGE=wesnoth PACKAGE=wesnoth
MAJOR_VERSION="0" MAJOR_VERSION="0"
MINOR_VERSION="6RC2" MINOR_VERSION="6RC3"
MICRO_VERSION="" MICRO_VERSION=""
if test "x$MICRO_VERSION" = "x"; then if test "x$MICRO_VERSION" = "x"; then

View file

@ -6,7 +6,7 @@ AC_INIT(wesnoth, 0.5, davidnwhite@optusnet.com.au, Battle for Wesnoth)
AC_REVISION($Version: 0.5$) AC_REVISION($Version: 0.5$)
PACKAGE=wesnoth PACKAGE=wesnoth
MAJOR_VERSION="0" MAJOR_VERSION="0"
MINOR_VERSION="6RC2" MINOR_VERSION="6RC3"
MICRO_VERSION="" MICRO_VERSION=""
if test "x$MICRO_VERSION" = "x"; then if test "x$MICRO_VERSION" = "x"; then

View file

@ -14,7 +14,7 @@
{STORM_TRIDENT 10 5} {STORM_TRIDENT 10 5}
[side] [side]
type=Commander type=Fighter
description=Konrad description=Konrad
side=1 side=1
canrecruit=1 canrecruit=1

View file

@ -25,7 +25,6 @@ Defeat
side=1 side=1
canrecruit=1 canrecruit=1
controller=human controller=human
recruit=Elvish Scout,Elvish Fighter,Elvish Archer,Horseman,Mage,Elvish Shaman,Thief,Merman
enemy=2,3 enemy=2,3
[/side] [/side]

View file

@ -19,6 +19,7 @@
objectives=" objectives="
Victory: Victory:
@Defeat both enemy leaders @Defeat both enemy leaders
@Defeat at least one enemy leader, and resist until time expires
Defeat: Defeat:
#Death of Konrad #Death of Konrad
#Turns run out" #Turns run out"
@ -499,12 +500,18 @@ The main cage where they keep most of the mermen is in the south-east!"
[/message] [/message]
[/event] [/event]
[event] #the ship they came on.
name=victory [item]
x=30
y=7
image=galleon.png
[/item]
#define BAY_OF_PEARLS_VICTORY
[message] [message]
id=msg3_16 id=msg3_16
description=Konrad description=Konrad
message=At last, we have freed the mermen. Go back to the ocean and leave in peace. message=At last, we have freed the mermen. Go back to the ocean and live in peace.
[/message] [/message]
[role] [role]
type=Merman Lord,Merman type=Merman Lord,Merman
@ -545,7 +552,7 @@ The main cage where they keep most of the mermen is in the south-east!"
[message] [message]
id=msg3_22 id=msg3_22
description=Konrad description=Konrad
message=Oh no! What should we do? message=Oh no! What shall we do?
[/message] [/message]
[message] [message]
@ -573,7 +580,7 @@ The main cage where they keep most of the mermen is in the south-east!"
[/message] [/message]
[role] [role]
type=Elvish Champion,Elvish Marshal,Elvish Captain,Elvish Hero,Knight,Elvish Outrider,Paladin,Mage,White Mage,Red Mage type=Elvish Champion,Elvish Marshal,Elvish Captain,Elvish Hero,Knight,Elvish Outrider,Paladin,Mage,White Mage,Red Mage,Elvish Fighter,Elvish Archer,Elvish Shaman,Horseman
role=Supporter role=Supporter
[/role] [/role]
[message] [message]
@ -587,18 +594,215 @@ The main cage where they keep most of the mermen is in the south-east!"
message=You will prevail. I have faith in you. Travel north. Elensefar is but three days travel if you make haste. message=You will prevail. I have faith in you. Travel north. Elensefar is but three days travel if you make haste.
[/message] [/message]
[message] [message]
id=msg3_29 id=msg3_29a
description=Konrad description=Konrad
message=Very well. Until we meet again, my dear friend! message=Very well. But how do I get to Elensefar?
[/message] [/message]
[message] [message]
id=msg3_30 id=msg3_30a
description=Delfador description=Delfador
message=Farewell, prince. message=It is north-west of here, but a few leagues inland from the coast. There are two ways you may get there, by ship, or by land. Each way has its own dangers and perils. You must choose how you wish to get there.
[option]
id=msg3_30_optiona
message="Ships? Ugh! I have been sea sick for the last time. We shall walk!"
[command]
[message]
id=msg3_30_farewell
description=Delfador
message=Safe journey to you, Konrad. Until we meet again!
[/message] [/message]
[/command]
[command]
[kill] [kill]
description=Delfador description=Delfador
[/kill] [/kill]
[/command]
[command]
[endlevel]
result=victory
next_scenario=Muff_Malals_Peninsula
bonus=yes
[/endlevel]
[/command]
[/option]
[option]
id=msg3_30_optionb
message="At least going by ship we may get a little rest for ourselves. By sea it is!"
[command]
[message]
id=msg3_30_farewella
description=Delfador
message=Safe voyage to you then, Konrad. May the weather be fair.
[/message]
[/command]
[command]
[kill]
description=Delfador
[/kill]
[/command]
[command]
[endlevel]
result=victory
next_scenario=Isle_of_the_Damned
bonus=yes
[/endlevel]
[/command]
[/option]
[/message]
#enddef
#track which enemy leaders are dead
[event]
name=die
[filter]
description=Dwaba-Kukai
[/filter]
[if]
[variable]
name=land_orc_dead
equals=yes
[/variable]
[then]
{BAY_OF_PEARLS_VICTORY}
[/then]
[else]
[set_variable]
name=sea_orc_dead
value=yes
[/set_variable]
[/else]
[/if]
[/event]
[event]
name=die
[filter]
description=Managa'Gwin
[/filter]
[if]
[variable]
name=sea_orc_dead
equals=yes
[/variable]
[then]
{BAY_OF_PEARLS_VICTORY}
[/then]
[else]
[set_variable]
name=land_orc_dead
value=yes
[/set_variable]
[/else]
[/if]
[/event]
[event]
name=time over
[command]
[unit]
x=18
y=1
description=Delfador
type=Elder Mage
[/unit]
[/command]
[command]
#if neither of the enemies are dead, automatically lose
[if]
[variable]
name=sea_orc_dead
not_equals=yes
[/variable]
[variable]
name=land_orc_dead
not_equals=yes
[/variable]
[then]
[message]
id=msg3_31
description=Delfador
message="Have you not been able to defeat our foes in all these days? They have summoned reinforcements. Surely now our doom is upon us!"
[/message]
[endlevel]
result=defeat
[/endlevel]
[/then]
#if we have killed at least one Orcish leader, we
#go on to the next scenario
[else]
[command]
[message]
id=msg3_32
description=Delfador
message="Konrad! We cannot spend anymore time here. Though it would be good to defeat the Orcs and free all we can, more urgent business calls us!"
[/message]
[message]
id=msg3_33
description=Konrad
message=Delfador, thank goodness you have survived! This has been a tough battle, but why can we not finish it? Why must we leave?
[/message]
[message]
id=msg3_34
description=Delfador
message=I bear ill tidings: Asheviere has attacked the city of Elensefar, breaking the treaty between Wesnoth and Elensefar. You must lead our men to the city, to help defend it -- or to recapture it if it falls before you arrive.
[/message]
[message]
id=msg3_35
description=Konrad
message=I must do this? But you are coming with me, aren't you, Delfador?
[/message]
[message]
id=msg3_36
description=Delfador
message=I am afraid not Konrad. I have found some important documents that need seeing to. I must ride at once to make council with the Elves. I will meet you in Elensefar, after you have secured it.
[/message]
[message]
id=msg3_37
description=Konrad
message=I fear I will struggle to do this on my own, but what must be must be. How do I get to Elensefar?
[/message]
[/command]
#if we killed the orc at sea, we travel by ship
#if we killed the orc on land, we travel by land
[command]
[if]
[variable]
name=sea_orc_dead
equals=yes
[/variable]
[then]
[message]
id=msg3_38
description=Delfador
message="Since you have broken the Orc's hegemony over the seas, going by ship would be safest. Sail along the coast, and you can land mere miles from Elensefar. Make haste!"
[/message]
[endlevel]
result=victory
next_scenario=Isle_of_the_Damned
[/endlevel]
[/then]
[else]
[message]
id=msg3_39
description=Delfador
message="With the Orcs controlling the seas, going by ship would not be safe. Travel by land, Elensefar is only six day's march up the coast. Make haste!"
[/message]
[endlevel]
result=victory
next_scenario=Muff_Malals_Peninsula
[/endlevel]
[/else]
[/if]
[/command]
[/else]
[/if]
[/command]
[/event] [/event]
[/scenario] [/scenario]

View file

@ -17,11 +17,7 @@
[bigmap] [bigmap]
image=misc/map.png image=misc/map.png
[dot] {CROSS 378 140}
type=cross
x=187
y=187
[/dot]
[/bigmap] [/bigmap]
objectives=" objectives="
@ -74,7 +70,6 @@ Defeat:
side=1 side=1
canrecruit=1 canrecruit=1
controller=human controller=human
recruit=Elvish Scout,Elvish Fighter,Elvish Archer,Horseman,Mage,Elvish Shaman,Merman,Thief,Gryphon Rider
enemy=2,3,4 enemy=2,3,4
[/side] [/side]

View file

@ -39,7 +39,7 @@ Defeat:
[/bigmap] [/bigmap]
[side] [side]
type=Commander type=Fighter
description=Konrad description=Konrad
side=1 side=1
canrecruit=1 canrecruit=1
@ -62,11 +62,11 @@ Defeat:
[target] [target]
description=Delfador description=Delfador
value=100 value=100
[end] [/target]
[target] [target]
description=Konrad description=Konrad
value=100 value=100
[end] [/target]
#enddef #enddef
#else #else
#define HIGH_PRIORITY_TARGETS #define HIGH_PRIORITY_TARGETS
@ -205,7 +205,7 @@ Defeat:
id=msg1_9hard id=msg1_9hard
description=Knafa-Tan description=Knafa-Tan
message="Remember, it is rumored that the filthy mage, and one that he protects is in these parts. They are the ones we want!" message="Remember, it is rumored that the filthy mage, and one that he protects is in these parts. They are the ones we want!"
[end] [/message]
#else #else
[message] [message]
id=msg1_9 id=msg1_9

View file

@ -17,11 +17,10 @@
[bigmap] [bigmap]
image=misc/map.png image=misc/map.png
[dot] {DOT 305 202}
type=cross {DOT 313 195}
x=187 {DOT 321 188}
y=187 {CROSS 321 182}
[/dot]
[/bigmap] [/bigmap]
objectives=" objectives="
@ -38,7 +37,7 @@ Defeat:
side=1 side=1
canrecruit=1 canrecruit=1
controller=human controller=human
recruit=Elvish Scout,Elvish Fighter,Elvish Archer,Horseman,Mage,Elvish Shaman,Merman,Thief,Gryphon Rider recruit=Gryphon Rider
enemy=2,3 enemy=2,3
[/side] [/side]

View file

@ -26,6 +26,10 @@ Defeat:
[bigmap] [bigmap]
image=misc/map.png image=misc/map.png
[dot] [dot]
{DOT 262 225}
{DOT 272 214}
{DOT 288 207}
{CROSS 298 208}
type=cross type=cross
x=187 x=187
y=187 y=187
@ -63,7 +67,6 @@ Defeat:
side=1 side=1
canrecruit=1 canrecruit=1
controller=human controller=human
recruit=Elvish Scout,Elvish Fighter,Elvish Archer,Horseman,Mage,Merman,Thief
enemy=2,3 enemy=2,3
[/side] [/side]

View file

@ -34,7 +34,6 @@ Defeat:
side=1 side=1
canrecruit=1 canrecruit=1
controller=human controller=human
recruit=Elvish Scout,Elvish Fighter,Elvish Archer,Horseman,Mage,Elvish Shaman,Merman,Thief,Gryphon Rider,Dwarvish Fighter,Dwarvish Thunderer
enemy=3 enemy=3
shroud=yes shroud=yes
[/side] [/side]

View file

@ -0,0 +1,170 @@
[scenario]
{DAWN}
{MORNING}
{AFTERNOON}
{DUSK}
{FIRST_WATCH}
{SECOND_WATCH}
id=Isle_of_the_Damned
next_scenario=The_Siege_of_Elensefar
name=Isle of the Damned
map=isle_damned
turns=24
music="wesnoth-3.ogg"
objectives="
Victory:
@Defeat both enemy leaders
@Resist until the end of the turns
Defeat:
#Death of Konrad"
disallow_recall=yes
[bigmap]
image=misc/map.png
{DOT 162 367}
{DOT 158 372}
{DOT 151 379}
{DOT 137 385}
{DOT 122 383}
{DOT 109 377}
{DOT 99 369}
{DOT 94 374}
{CROSS 93 386}
[/bigmap]
[side]
description=Konrad
type=Commander
side=1
canrecruit=1
enemy=2,3
controller=human
[unit]
description=Kalba
type=Merman
side=1
x=25
y=10
[/unit]
[unit]
description=Gnaba
type=Merman
side=1
x=29
y=12
[/unit]
[/side]
[side]
description=Haf-Mal
type=Lich
side=2
canrecruit=1
enemy=1
recruit=Skeleton,Vampire Bat,Ghost,Dark Adept,Chocobone
recruitment_pattern=scout,scout,fighter
{GOLD 80 140 200}
[/side]
[side]
description=Jarmal-Gorg
type=Lich
side=3
canrecruit=1
enemy=1
recruit=Skeleton,Skeleton Archer,Walking Corpse,Vampire Bat,Ghost,Dark Adept
{GOLD 80 140 200}
[/side]
[story]
[part]
id=isledamn_1
story="But the voyage did not go as smoothly as had been hoped. A storm lashed down on the ship, all hands were on deck, trying desperately to save the ship. As Konrad attempted to secure the mast, a sudden gust of wind flung him overboard..."
image="misc/map.png"
[/part]
[part]
id=isledamn_2
story="The mermen saved Konrad from the seas, but were not able to get him back to the ship. Instead, they had to resort to taking him to a nearby island..."
image="misc/map.png"
[/part]
[/story]
[event]
name=start
[message]
description=Konrad
id=isledamn_3
message="Whew, I survived. But now where am I? Is this island inhabited?"
[/message]
[message]
description=Kalba
id=isledamn_4
message="There have been ill tidings about this island, my lord. It is said that the fiends of the undead have overtaken it, and it has fallen into ugly wasteland."
[/message]
[message]
description=Konrad
id=isledamn_5
message="Let us hope these rumors are not true! I have none of my men with me! How would I defend myself?"
[/message]
[message]
description=Kalba
id=isledamn_6
message="There are still some Elves on this island, my lord, perhaps if you recruit some of them to help you, we might have some hope of holding off the undead hordes!"
[/message]
[/event]
#define ISLE_GALLEON_ARRIVE
[command]
[move_unit_fake]
type=Galleon
x=23,23,23,23,23,24
y=1,2,3,4,5,5
[/move_unit_fake]
[/command]
[command]
[item]
x=24
y=5
image=galleon.png
[/item]
[/command]
#enddef
[event]
name=enemies defeated
[command]
[message]
description=Konrad
message="We have wrested control of the island from the evil undead! Now all we have to do is wait for the ship to arrive, so we can make our way to Elensefar!"
[/message]
[/command]
{ISLE_GALLEON_ARRIVE}
[/event]
[event]
name=time over
{ISLE_GALLEON_ARRIVE}
[command]
[message]
speaker=narrator
image=elvish-fighter.png
message="Thank goodness we have found you, sir! Come aboard quickly, we shall take you away from this horrible island!"
[/message]
[/command]
[command]
[message]
description=Konrad
message="It is a shame complete victory could not be ours, but thank goodness I am rescued! On to Elensefar!"
[/message]
[/command]
[command]
[endlevel]
result=victory
[/endlevel]
[/command]
[/event]
[/scenario]

View file

@ -17,11 +17,9 @@
[bigmap] [bigmap]
image=misc/map.png image=misc/map.png
[dot] {DOT 354 167}
type=cross {DOT 355 157}
x=187 {CROSS 356 147}
y=187
[/dot]
[/bigmap] [/bigmap]
objectives=" objectives="
@ -38,7 +36,6 @@ Defeat:
side=1 side=1
canrecruit=1 canrecruit=1
controller=human controller=human
recruit=Elvish Scout,Elvish Fighter,Elvish Archer,Horseman,Mage,Elvish Shaman,Merman,Thief,Gryphon Rider
enemy=2,3 enemy=2,3
fog=yes fog=yes
[/side] [/side]
@ -61,15 +58,8 @@ Defeat:
recruitment_pattern=fighter recruitment_pattern=fighter
villages_per_scout=0 villages_per_scout=0
#ifdef EASY {GOLD 150 200 280}
gold=150
#endif
#ifdef NORMAL
gold=200
#endif
#ifdef HARD
gold=280
#endif
enemy=1 enemy=1
[/side] [/side]
@ -87,18 +77,8 @@ Defeat:
#endif #endif
recruitment_pattern=fighter,scout,scout,mixed fighter recruitment_pattern=fighter,scout,scout,mixed fighter
villages_per_scout=0 villages_per_scout=0
#ifdef EASY {GOLD 150 250 350}
gold=200 {INCOME 15 30 50}
income=20
#endif
#ifdef NORMAL
gold=250
income=30
#endif
#ifdef HARD
gold=350
income=50
#endif
enemy=1 enemy=1
village_value=0 village_value=0
leader_value=10 leader_value=10

View file

@ -27,7 +27,7 @@ Defeat:
image=misc/map.png image=misc/map.png
{DOT 164 348} {DOT 164 348}
{DOT 158 340} {DOT 158 340}
{DOT 142 355} {DOT 142 338}
{DOT 127 340} {DOT 127 340}
{CROSS 122 331} {CROSS 122 331}
[/bigmap] [/bigmap]
@ -224,6 +224,11 @@ Defeat:
[kill] [kill]
description=Moremirmu description=Moremirmu
[/kill] [/kill]
[message]
id=msg4_12b
description=Konrad
message="Victory is ours! Let us just hope that this delay will not hamper our quest to save Elensefar. We must move onward with haste!"
[/message]
[/event] [/event]
[event] [event]
name=die name=die

View file

@ -26,11 +26,9 @@ Defeat:
[bigmap] [bigmap]
image=misc/map.png image=misc/map.png
[dot] {DOT 336 180}
type=cross {DOT 344 174}
x=77 {CROSS 354 167}
y=235
[/dot]
[/bigmap] [/bigmap]
[side] [side]
@ -41,7 +39,6 @@ Defeat:
experience=0 experience=0
side=1 side=1
canrecruit=1 canrecruit=1
recruit=Elvish Scout,Elvish Fighter,Elvish Archer,Horseman,Mage,Elvish Shaman,Merman,Thief,Gryphon Rider
enemy=2,3 enemy=2,3
controller=human controller=human
[/side] [/side]

View file

@ -33,7 +33,6 @@ Defeat
side=1 side=1
canrecruit=1 canrecruit=1
controller=human controller=human
recruit=Elvish Scout,Elvish Fighter,Elvish Archer,Horseman,Mage,Elvish Shaman,Merman,Thief,Gryphon Rider
enemy=2 enemy=2
shroud=yes shroud=yes
[/side] [/side]

View file

@ -53,7 +53,6 @@ Defeat:
side=1 side=1
canrecruit=1 canrecruit=1
controller=human controller=human
recruit=Elvish Scout,Elvish Fighter,Elvish Archer,Horseman,Mage,Elvish Shaman,Merman,Thief
enemy=2 enemy=2
[/side] [/side]

View file

@ -34,7 +34,6 @@ Defeat:
side=1 side=1
canrecruit=1 canrecruit=1
controller=human controller=human
recruit=Elvish Scout,Elvish Fighter,Elvish Archer,Horseman,Mage,Elvish Shaman,Merman,Thief,Gryphon Rider,Dwarvish Fighter,Dwarvish Thunderer
enemy=2,3,4,5,6 enemy=2,3,4,5,6
shroud=yes shroud=yes
[/side] [/side]
@ -48,20 +47,8 @@ Defeat:
recruit=Goblin Knight,Wolf Rider,Troll,Orcish Warrior,Orcish Crossbow recruit=Goblin Knight,Wolf Rider,Troll,Orcish Warrior,Orcish Crossbow
enemy=1 enemy=1
#ifdef EASY {GOLD 150 300 400}
gold=300 {INCOME 5 10 20}
income=10
#endif
#ifdef MEDIUM
gold=400
income=20
#endif
#ifdef HARD
gold=550
income=30
#endif
[/side] [/side]
[side] [side]
type=Troll Warrior type=Troll Warrior
@ -72,21 +59,8 @@ Defeat:
recruitment_pattern=fighter recruitment_pattern=fighter
recruit=Troll,Troll Warrior,Ogre recruit=Troll,Troll Warrior,Ogre
enemy=1 enemy=1
{GOLD 150 300 400}
#ifdef EASY {INCOME 5 10 20}
gold=300
income=10
#endif
#ifdef MEDIUM
gold=400
income=20
#endif
#ifdef HARD
gold=550
income=30
#endif
[/side] [/side]
[side] [side]
@ -99,20 +73,8 @@ Defeat:
recruit=Troll,Troll Warrior,Ogre,Goblin Knight,Wolf Rider,Troll Whelp recruit=Troll,Troll Warrior,Ogre,Goblin Knight,Wolf Rider,Troll Whelp
enemy=1 enemy=1
#ifdef EASY {GOLD 150 230 350}
gold=200 {INCOME 5 10 20}
income=10
#endif
#ifdef MEDIUM
gold=300
income=20
#endif
#ifdef HARD
gold=450
income=30
#endif
[/side] [/side]
[side] [side]
@ -124,21 +86,8 @@ Defeat:
recruitment_pattern=fighter,fighter,scout recruitment_pattern=fighter,fighter,scout
recruit=Troll,Troll Warrior,Ogre,Goblin Knight,Wolf Rider,Troll Whelp recruit=Troll,Troll Warrior,Ogre,Goblin Knight,Wolf Rider,Troll Whelp
enemy=1 enemy=1
{GOLD 150 230 350}
#ifdef EASY {INCOME 5 10 20}
gold=200
income=15
#endif
#ifdef MEDIUM
gold=300
income=20
#endif
#ifdef HARD
gold=450
income=30
#endif
[/side] [/side]
#dummy enemy that forces finding the Sceptre #dummy enemy that forces finding the Sceptre

View file

@ -123,7 +123,7 @@ Defeat:
[/message] [/message]
[message] [message]
id=msg5_4 id=msg5_4
description=Advisor role=Advisor
message=There are so many of them. This will not be easy! And look to the south, it seems that the undead are allied with the Orcs! message=There are so many of them. This will not be easy! And look to the south, it seems that the undead are allied with the Orcs!
[/message] [/message]
[message] [message]
@ -139,7 +139,7 @@ Defeat:
[/event] [/event]
[event] [event]
name=turn 6 name=turn 5
[unit] [unit]
description=Reglok description=Reglok
type=Thief type=Thief
@ -178,7 +178,7 @@ Defeat:
[/message] [/message]
[message] [message]
id=msg5_10 id=msg5_10
description=Advisor role=Advisor
message=Thieves hmmm? Who says we can trust such as you? message=Thieves hmmm? Who says we can trust such as you?
[/message] [/message]
[message] [message]
@ -187,9 +187,41 @@ Defeat:
message=We would understand if you don't trust us, of course, but it is in both our best interests to rid the city of the Orcs! message=We would understand if you don't trust us, of course, but it is in both our best interests to rid the city of the Orcs!
[/message] [/message]
[message] [message]
id=msg5_12 id=msg5_12a
description=Konrad description=Konrad
message=Very well, you may join us. message=Hmm...I have to consider this...
[option]
id=accept_thieves
message="Very well. You may join us."
[command]
[message]
id=msg5_13
description=Gamlel
message=We will serve you well, for we respect the help you are providing to our city. You shall find that there is honor, even among thieves.
[/message]
[set_variable]
name=have_thieves
value=yes
[/set_variable]
[can_recruit]
type=Thief
[/can_recruit]
[/command]
[/option]
[option]
id=reject_thieves
message="We cannot trust your motives. We shall rescue the city on our own!"
[command]
[message]
id=msg5_14
description=Gamlel
message="Very well, we shall begone then. You shall have to recapture the city without our help!"
[/message]
[kill]
type=Thief
[/kill]
[/command]
[/option]
[/message] [/message]
[/event] [/event]

View file

@ -26,7 +26,6 @@ Defeat
side=1 side=1
canrecruit=1 canrecruit=1
controller=human controller=human
recruit=Elvish Scout,Elvish Fighter,Elvish Archer,Horseman,Mage,Elvish Shaman,Thief,Merman
enemy=2,3 enemy=2,3
[/side] [/side]

View file

@ -27,7 +27,6 @@ Defeat
canrecruit=1 canrecruit=1
controller=human controller=human
hitpoints=80 hitpoints=80
recruit=Elvish Scout,Elvish Fighter,Elvish Archer,Horseman,Mage,Elvish Shaman,Thief,Merman
enemy=2,3,4,5,6 enemy=2,3,4,5,6
[/side] [/side]

View file

@ -33,7 +33,7 @@ Defeat:
side=1 side=1
canrecruit=1 canrecruit=1
controller=human controller=human
recruit=Elvish Scout,Elvish Fighter,Elvish Archer,Horseman,Mage,Elvish Shaman,Merman,Thief,Gryphon Rider,Dwarvish Fighter,Dwarvish Thunderer recruit=Dwarvish Fighter,Dwarvish Thunderer
enemy=3,4 enemy=3,4
shroud=yes shroud=yes
[/side] [/side]

View file

@ -25,11 +25,10 @@ Defeat:
[bigmap] [bigmap]
image=misc/map.png image=misc/map.png
[dot] {DOT 250 255}
type=cross {DOT 251 246}
x=207 {DOT 253 239}
y=147 {CROSS 253 231}
[/dot]
[/bigmap] [/bigmap]
[side] [side]
@ -38,7 +37,6 @@ Defeat:
side=1 side=1
canrecruit=1 canrecruit=1
controller=human controller=human
recruit=Elvish Scout,Elvish Fighter,Elvish Archer,Horseman,Mage,Elvish Shaman,Merman,Thief
recruitment_pattern=scout,fighter,archer recruitment_pattern=scout,fighter,archer
aggression=-0.5 aggression=-0.5
village_value=1.0 village_value=1.0

View file

@ -20,7 +20,7 @@ Defeat:
[side] [side]
race=Elves race=Elves
type=Commander type=Fighter
description=Konrad description=Konrad
experience=0 experience=0
side=1 side=1

View file

@ -7,7 +7,7 @@ hitpoints=45
ability=leadership ability=leadership
movement_type=smallfoot movement_type=smallfoot
movement=6 movement=6
experience=80 experience=60
level=2 level=2
alignment=lawful alignment=lawful
advanceto=Lord advanceto=Lord
@ -29,15 +29,15 @@ get_hit_sound=groan.wav
name=sword name=sword
type=blade type=blade
range=short range=short
damage=6 damage=8
number=4 number=4
[frame] [frame]
begin=-350 begin=-250
end=-300 end=-200
image=konrad-commander.png image=konrad-commander.png
[/frame] [/frame]
[frame] [frame]
begin=-300 begin=-200
end=-100 end=-100
image="konrad-commander-attack1.png" image="konrad-commander-attack1.png"
[/frame] [/frame]
@ -66,7 +66,7 @@ get_hit_sound=groan.wav
name=bow name=bow
type=pierce type=pierce
range=long range=long
damage=3 damage=6
number=3 number=3
[sound] [sound]
time=-100 time=-100

39
data/units/Fighter.cfg Normal file
View file

@ -0,0 +1,39 @@
[unit]
name=Fighter
race=human
image=konrad-young.png
profile=misc/konrad.png
hitpoints=32
movement_type=smallfoot
movement=6
experience=28
level=1
alignment=lawful
advanceto=Commander
cost=100
usage=mixed fighter
unit_description="The fighter is skilled with use of the sword in battle. Young and brash, he is vulnerable to attack from enemies. However he has the potential to one day become a great warrior"
get_hit_sound=groan.wav
[attack]
name=sword
type=blade
range=short
damage=6
number=3
[frame]
begin=-250
end=-100
image=konrad-young.png
[/frame]
[frame]
begin=-100
end=50
image="konrad-young-attack.png"
[/frame]
[sound]
time=-250
sound=sword-swish.wav
[/sound]
[/attack]
[/unit]

View file

@ -12,7 +12,7 @@ alignment=chaotic
advanceto=null advanceto=null
cost=22 cost=22
usage=scout usage=scout
unit_desc="Some goblins train their wolves to dont fear file. Wielding tochs and nets goblin pillager bring havok to his enemies." unit_description="Some goblins train their wolves to overcome their fear of fire. Wielding torches and nets, Goblin Pillagers bring havoc to their enemies."
get_hit_sound=groan.wav get_hit_sound=groan.wav
[attack] [attack]
name=torch name=torch

View file

@ -3,7 +3,7 @@ name=Lord
race=human race=human
image=konrad-lord.png image=konrad-lord.png
profile=misc/konrad.png profile=misc/konrad.png
hitpoints=65 hitpoints=68
ability=leadership ability=leadership
movement_type=smallfoot movement_type=smallfoot
movement=6 movement=6
@ -19,7 +19,7 @@ get_hit_sound=groan.wav
name=sword name=sword
type=blade type=blade
range=short range=short
damage=11 damage=14
number=4 number=4
[/attack] [/attack]
[attack] [attack]

View file

@ -20,5 +20,10 @@ usage=fighter
range=short range=short
damage=14 damage=14
number=2 number=2
[frame]
begin=-100
end=100
image=troll-grunt-attack.png
[/frame]
[/attack] [/attack]
[/unit] [/unit]

Binary file not shown.

After

Width:  |  Height:  |  Size: 707 B

View file

@ -341,15 +341,72 @@ void attack(display& gui, const gamemap& map,
while(stats.nattacks > 0 || stats.ndefends > 0) { while(stats.nattacks > 0 || stats.ndefends > 0) {
if(stats.nattacks > 0) { if(stats.nattacks > 0) {
const bool hits = (get_random()%100) < stats.chance_to_hit_defender; const int ran_num = get_random();
const bool dies = gui.unit_attack(attacker,defender, bool hits = (ran_num%100) < stats.chance_to_hit_defender;
//make sure that if we're serializing a game here,
//we got the same results as the game did originally
const config* ran_results = get_random_results();
if(ran_results != NULL) {
const int results_chance = atoi((*ran_results)["chance"].c_str());
const bool results_hits = (*ran_results)["hits"] == "yes";
const int results_damage = atoi((*ran_results)["damage"].c_str());
if(results_chance != stats.chance_to_hit_defender) {
std::cerr << "SYNC ERROR: In attack " << a->second.type().name() << " vs "
<< d->second.type().name() << ": chance to hit defender is inconsistent. Data source: "
<< results_chance << "; Calculation: " << stats.chance_to_hit_defender
<< " (over-riding game calculations with data source results)\n";
hits = results_hits;
} else if(hits != results_hits) {
std::cerr << "SYNC ERROR: In attack " << a->second.type().name() << " vs "
<< d->second.type().name() << ": the data source says the hit was "
<< (results_hits ? "successful" : "unsuccessful") << ", while in-game calculations say the hit was "
<< (hits ? "successful" : "unsuccessful")
<< " random number: " << ran_num << " = " << (ran_num%100) << "/" << results_chance
<< " (over-riding game calculations with data source results)\n";
hits = results_hits;
} else if(results_damage != stats.damage_defender_takes) {
std::cerr << "SYNC ERROR: In attack " << a->second.type().name() << " vs "
<< d->second.type().name() << ": the data source says the hit did "
<< results_damage << " damage, while in-game calculations show the hit doing "
<< stats.damage_defender_takes << " damage (over-riding game calculations with data source results)\n";
stats.damage_defender_takes = results_damage;
}
}
bool dies = gui.unit_attack(attacker,defender,
hits ? stats.damage_defender_takes : 0, hits ? stats.damage_defender_takes : 0,
a->second.attacks()[attack_with]); a->second.attacks()[attack_with]);
if(ran_results == NULL) {
config cfg;
cfg["hits"] = (hits ? "yes" : "no");
cfg["dies"] = (dies ? "yes" : "no");
char buf[50];
sprintf(buf,"%d",stats.damage_defender_takes);
cfg["damage"] = buf;
sprintf(buf,"%d",stats.chance_to_hit_defender);
cfg["chance"] = buf;
set_random_results(cfg);
} else {
const bool results_dies = (*ran_results)["dies"] == "yes";
if(results_dies != dies) {
std::cerr << "SYNC ERROR: In attack" << a->second.type().name() << " vs "
<< d->second.type().name() << ": the data source the unit "
<< (results_dies ? "perished" : "survived") << " while in-game calculations show the unit "
<< (dies ? "perished" : "survived") << " (over-riding game calculations with data source results)\n";
dies = results_dies;
}
}
if(dies) { if(dies) {
attackerxp = 8*d->second.type().level(); attackerxp = 8*d->second.type().level();
if(d->second.type().level() == 0) if(d->second.type().level() == 0)
attackerxp = 4; attackerxp = 4;
a->second.get_experience(attackerxp);
attackerxp = 0;
defenderxp = 0; defenderxp = 0;
gamemap::location loc = d->first; gamemap::location loc = d->first;
@ -397,16 +454,72 @@ void attack(display& gui, const gamemap& map,
} }
if(stats.ndefends > 0) { if(stats.ndefends > 0) {
const bool hits = (get_random()%100) < stats.chance_to_hit_attacker; const int ran_num = get_random();
const bool dies = gui.unit_attack(defender,attacker, bool hits = (ran_num%100) < stats.chance_to_hit_attacker;
//make sure that if we're serializing a game here,
//we got the same results as the game did originally
const config* ran_results = get_random_results();
if(ran_results != NULL) {
const int results_chance = atoi((*ran_results)["chance"].c_str());
const bool results_hits = (*ran_results)["hits"] == "yes";
const int results_damage = atoi((*ran_results)["damage"].c_str());
if(results_chance != stats.chance_to_hit_attacker) {
std::cerr << "SYNC ERROR: In defend " << a->second.type().name() << " vs "
<< d->second.type().name() << ": chance to hit attacker is inconsistent. Data source: "
<< results_chance << "; Calculation: " << stats.chance_to_hit_attacker
<< " (over-riding game calculations with data source results)\n";
hits = results_hits;
} else if(hits != results_hits) {
std::cerr << "SYNC ERROR: In defend " << a->second.type().name() << " vs "
<< d->second.type().name() << ": the data source says the hit was "
<< (results_hits ? "successful" : "unsuccessful") << ", while in-game calculations say the hit was "
<< (hits ? "successful" : "unsuccessful")
<< " random number: " << ran_num << " = " << (ran_num%100) << "/" << results_chance
<< " (over-riding game calculations with data source results)\n";
hits = results_hits;
} else if(results_damage != stats.damage_attacker_takes) {
std::cerr << "SYNC ERROR: In defend " << a->second.type().name() << " vs "
<< d->second.type().name() << ": the data source says the hit did "
<< results_damage << " damage, while in-game calculations show the hit doing "
<< stats.damage_attacker_takes << " damage (over-riding game calculations with data source results)\n";
stats.damage_attacker_takes = results_damage;
}
}
bool dies = gui.unit_attack(defender,attacker,
hits ? stats.damage_attacker_takes : 0, hits ? stats.damage_attacker_takes : 0,
d->second.attacks()[stats.defend_with]); d->second.attacks()[stats.defend_with]);
if(ran_results == NULL) {
config cfg;
cfg["hits"] = (hits ? "yes" : "no");
cfg["dies"] = (dies ? "yes" : "no");
char buf[50];
sprintf(buf,"%d",stats.damage_attacker_takes);
cfg["damage"] = buf;
sprintf(buf,"%d",stats.chance_to_hit_attacker);
cfg["chance"] = buf;
set_random_results(cfg);
} else {
const bool results_dies = (*ran_results)["dies"] == "yes";
if(results_dies != dies) {
std::cerr << "SYNC ERROR: In defend" << a->second.type().name() << " vs "
<< d->second.type().name() << ": the data source the unit "
<< (results_dies ? "perished" : "survived") << " while in-game calculations show the unit "
<< (dies ? "perished" : "survived") << " (over-riding game calculations with data source results)\n";
dies = results_dies;
}
}
if(dies) { if(dies) {
defenderxp = 8*a->second.type().level(); defenderxp = 8*a->second.type().level();
if(a->second.type().level() == 0) if(a->second.type().level() == 0)
defenderxp = 4; defenderxp = 4;
d->second.get_experience(defenderxp);
defenderxp = 0;
attackerxp = 0; attackerxp = 0;
gamemap::location loc = a->first; gamemap::location loc = a->first;
@ -742,6 +855,10 @@ void check_victory(std::map<gamemap::location,unit>& units,
} }
if(found_enemies == false) { if(found_enemies == false) {
if(found_human) {
game_events::fire("enemies defeated");
}
throw end_level_exception(found_human ? VICTORY : DEFEAT); throw end_level_exception(found_human ? VICTORY : DEFEAT);
} }

View file

@ -572,6 +572,17 @@ config::const_child_itors config::child_range(const std::string& key) const
} }
} }
const config::child_list& config::get_children(const std::string& key) const
{
const child_map::const_iterator i = children.find(key);
if(i != children.end()) {
return i->second;
} else {
static const child_list dummy;
return dummy;
}
}
config* config::child(const std::string& key) config* config::child(const std::string& key)
{ {
const child_map::const_iterator i = children.find(key); const child_map::const_iterator i = children.find(key);

View file

@ -108,6 +108,8 @@ struct config
child_itors child_range(const std::string& key); child_itors child_range(const std::string& key);
const_child_itors child_range(const std::string& key) const; const_child_itors child_range(const std::string& key) const;
const child_list& get_children(const std::string& key) const;
config* child(const std::string& key); config* child(const std::string& key);
const config* child(const std::string& key) const; const config* child(const std::string& key) const;
config& add_child(const std::string& key); config& add_child(const std::string& key);

View file

@ -1077,7 +1077,7 @@ void display::draw_tile(int x, int y, SDL_Surface* unit_image,
Pixel grid_colour = SDL_MapRGB(dst->format,0,0,0); Pixel grid_colour = SDL_MapRGB(dst->format,0,0,0);
const bool show_unit_colour = preferences::show_side_colours() && it != units_.end(); const bool show_unit_colour = preferences::show_side_colours() && !fogged(x,y) && it != units_.end();
if(show_unit_colour) { if(show_unit_colour) {
const SDL_Color& colour = font::get_side_colour(it->second.side()); const SDL_Color& colour = font::get_side_colour(it->second.side());
grid_colour = SDL_MapRGB(dst->format,colour.r,colour.g,colour.b); grid_colour = SDL_MapRGB(dst->format,colour.r,colour.g,colour.b);
@ -1344,13 +1344,14 @@ void display::draw_footstep(const gamemap::location& loc, int xloc, int yloc)
draw_unit(xloc,yloc,image,hflip,vflip,0.5); draw_unit(xloc,yloc,image,hflip,vflip,0.5);
if(show_time && route_.move_left > 0 && route_.move_left < 10) { if(show_time && route_.move_left > 0 && route_.move_left < 10) {
const SDL_Rect rect = {0,0,this->mapx(),this->y()};
static std::string str(1,'x'); static std::string str(1,'x');
str[0] = '0' + route_.move_left + 1; str[0] = '0' + route_.move_left + 1;
const SDL_Rect& text_area = const SDL_Rect& text_area =
font::draw_text(NULL,screen_area(),18,font::BUTTON_COLOUR,str,0,0); font::draw_text(NULL,rect,18,font::BUTTON_COLOUR,str,0,0);
const int x = xloc + int(zoom_/2.0) - text_area.w/2; const int x = xloc + int(zoom_/2.0) - text_area.w/2;
const int y = yloc + int(zoom_/2.0) - text_area.h/2; const int y = yloc + int(zoom_/2.0) - text_area.h/2;
font::draw_text(this,screen_area(),18,font::BUTTON_COLOUR,str,x,y); font::draw_text(this,rect,18,font::BUTTON_COLOUR,str,x,y);
} }
} }

View file

@ -64,7 +64,7 @@ LEVEL_RESULT play_game(display& disp, game_state& state, config& game_config,
try { try {
LEVEL_RESULT res = REPLAY; LEVEL_RESULT res = REPLAY;
state.label = scenario->values["name"]; state.label = translate_string_default((*scenario)["id"],(*scenario)["name"]);
recorder.set_save_info(state); recorder.set_save_info(state);
@ -122,7 +122,7 @@ LEVEL_RESULT play_game(display& disp, game_state& state, config& game_config,
//if this isn't the last scenario, then save the game //if this isn't the last scenario, then save the game
if(scenario != NULL) { if(scenario != NULL) {
state.label = (*scenario)["name"]; state.label = translate_string_default((*scenario)["id"],(*scenario)["name"]);
const int should_save = dialogs::get_save_name(disp, const int should_save = dialogs::get_save_name(disp,
string_table["save_game_message"], string_table["save_game_message"],

View file

@ -22,7 +22,7 @@ namespace game_config
const int cure_amount = 8; const int cure_amount = 8;
const int curer_heals_per_turn = 18; const int curer_heals_per_turn = 18;
const int recall_cost = 20; const int recall_cost = 20;
const std::string version = "0.6RC2"; const std::string version = "0.6RC3";
bool debug = false; bool debug = false;
#ifdef WESNOTH_PATH #ifdef WESNOTH_PATH

View file

@ -23,6 +23,7 @@
#include <cstdlib> #include <cstdlib>
#include <deque> #include <deque>
#include <iostream> #include <iostream>
#include <iterator>
#include <set> #include <set>
#include <string> #include <string>
@ -134,6 +135,7 @@ std::map<gamemap::location,unit>* units = NULL;
std::vector<team>* teams = NULL; std::vector<team>* teams = NULL;
game_state* state_of_game = NULL; game_state* state_of_game = NULL;
game_data* game_data_ptr = NULL; game_data* game_data_ptr = NULL;
std::set<std::string> used_items;
bool events_init() { return screen != NULL; } bool events_init() { return screen != NULL; }
@ -173,7 +175,7 @@ public:
return cfg_->children["filter_second"]; return cfg_->children["filter_second"];
} }
void handle_event(const queued_event& event_info, config* cfg=NULL); void handle_event(const queued_event& event_info, const config* cfg=NULL);
private: private:
std::string name_; std::string name_;
@ -218,31 +220,79 @@ std::vector<gamemap::location> multiple_locs(const config& cfg)
std::multimap<std::string,event_handler> events_map; std::multimap<std::string,event_handler> events_map;
void event_handler::handle_event(const queued_event& event_info, config* cfg) void event_handler::handle_event(const queued_event& event_info, const config* cfg)
{ {
if(cfg == NULL) if(cfg == NULL)
cfg = cfg_; cfg = cfg_;
std::vector<config*>::const_iterator i;
//sub commands that need to be handled in a guaranteed ordering //sub commands that need to be handled in a guaranteed ordering
std::vector<config*>& commands = cfg->children["command"]; const config::child_list& commands = cfg->get_children("command");
for(std::vector<config*>::iterator cmd = commands.begin(); for(i = commands.begin(); i != commands.end(); ++i) {
cmd != commands.end(); ++cmd) { handle_event(event_info,*i);
handle_event(event_info,*cmd); }
//allow a side to recruit a new type of unit
const config::child_list& allow_recruit = cfg->get_children("allow_recruit");
for(i = allow_recruit.begin(); i != allow_recruit.end(); ++i) {
const int side = maximum<int>(1,atoi((**i)["side"].c_str()));
const size_t index = side-1;
if(index > teams->size())
continue;
const std::string& type = (**i)["type"];
(*teams)[index].recruits().insert(type);
if(index == 0) {
state_of_game->can_recruit.insert(type);
}
}
//remove the ability to recruit a unit from a certain side
const config::child_list& disallow_recruit = cfg->get_children("disallow_recruit");
for(i = disallow_recruit.begin(); i != disallow_recruit.end(); ++i) {
const int side = maximum<int>(1,atoi((**i)["side"].c_str()));
const size_t index = side-1;
if(index > teams->size())
continue;
const std::string& type = (**i)["type"];
(*teams)[index].recruits().erase(type);
if(index == 0) {
state_of_game->can_recruit.erase(type);
}
}
const config::child_list& set_recruit = cfg->get_children("set_recruit");
for(i = set_recruit.begin(); i != set_recruit.end(); ++i) {
const int side = maximum<int>(1,atoi((**i)["side"].c_str()));
const size_t index = side-1;
if(index > teams->size())
continue;
std::vector<std::string> recruit = config::split((**i)["recruit"]);
if(recruit.size() == 1 && recruit.back() == "")
recruit.clear();
std::set<std::string>& can_recruit = (*teams)[index].recruits();
can_recruit.clear();
std::copy(recruit.begin(),recruit.end(),std::inserter(can_recruit,can_recruit.end()));
if(index == 0) {
state_of_game->can_recruit = can_recruit;
}
} }
//sounds //sounds
std::vector<config*>& sounds = cfg->children["sound"]; const config::child_list& sounds = cfg->get_children("sound");
for(std::vector<config*>::iterator sfx = sounds.begin(); for(i = sounds.begin(); i != sounds.end(); ++i) {
sfx != sounds.end(); ++sfx) { sound::play_sound((**i)["name"]);
sound::play_sound((*sfx)->values["name"]);
} }
std::vector<config*>& colour_adjust = cfg->children["colour_adjust"]; const config::child_list& colour_adjust = cfg->get_children("colour_adjust");
for(std::vector<config*>::const_iterator col = colour_adjust.begin(); for(i = colour_adjust.begin(); i != colour_adjust.end(); ++i) {
col != colour_adjust.end(); ++col) { const int r = atoi((**i)["red"].c_str());
const int r = atoi((**col)["red"].c_str()); const int g = atoi((**i)["green"].c_str());
const int g = atoi((**col)["green"].c_str()); const int b = atoi((**i)["blue"].c_str());
const int b = atoi((**col)["blue"].c_str());
screen->adjust_colours(r,g,b); screen->adjust_colours(r,g,b);
screen->invalidate_all(); screen->invalidate_all();
screen->draw(true,true); screen->draw(true,true);
@ -276,11 +326,10 @@ void event_handler::handle_event(const queued_event& event_info, config* cfg)
} }
//an award of gold to a particular side //an award of gold to a particular side
std::vector<config*>& gold = cfg->children["gold"]; const config::child_list& gold = cfg->get_children("gold");
for(std::vector<config*>::iterator gd = gold.begin(); gd!=gold.end();++gd) { for(i = gold.begin(); i != gold.end(); ++i) {
string_map& values = (*gd)->values; const std::string& side = (**i)["side"];
const std::string& side = values["side"]; const std::string& amount = (**i)["amount"];
const std::string& amount = values["amount"];
const int side_num = side.empty() ? 1 : atoi(side.c_str()); const int side_num = side.empty() ? 1 : atoi(side.c_str());
const int amount_num = atoi(amount.c_str()); const int amount_num = atoi(amount.c_str());
const size_t team_index = side_num-1; const size_t team_index = side_num-1;
@ -291,16 +340,14 @@ void event_handler::handle_event(const queued_event& event_info, config* cfg)
//moving a 'unit' - i.e. a dummy unit that is just moving for //moving a 'unit' - i.e. a dummy unit that is just moving for
//the visual effect //the visual effect
std::vector<config*>& move_unit_fake = cfg->children["move_unit_fake"]; const config::child_list& move_unit_fake = cfg->get_children("move_unit_fake");
for(std::vector<config*>::iterator muf = move_unit_fake.begin(); for(i = move_unit_fake.begin(); i != move_unit_fake.end(); ++i) {
muf != move_unit_fake.end(); ++muf) { const std::string& type = (**i)["type"];
const std::string& type = (*muf)->values["type"]; const game_data::unit_type_map::const_iterator itor = game_data_ptr->unit_types.find(type);
const game_data::unit_type_map::const_iterator itor =
game_data_ptr->unit_types.find(type);
if(itor != game_data_ptr->unit_types.end()) { if(itor != game_data_ptr->unit_types.end()) {
unit dummy_unit(&itor->second,0); unit dummy_unit(&itor->second,0);
const std::vector<std::string> xvals = config::split((*muf)->values["x"]); const std::vector<std::string> xvals = config::split((**i)["x"]);
const std::vector<std::string> yvals = config::split((*muf)->values["y"]); const std::vector<std::string> yvals = config::split((**i)["y"]);
std::vector<gamemap::location> path; std::vector<gamemap::location> path;
for(size_t i = 0; i != minimum(xvals.size(),yvals.size()); ++i) { for(size_t i = 0; i != minimum(xvals.size(),yvals.size()); ++i) {
path.push_back(gamemap::location(atoi(xvals[i].c_str())-1, path.push_back(gamemap::location(atoi(xvals[i].c_str())-1,
@ -312,17 +359,16 @@ void event_handler::handle_event(const queued_event& event_info, config* cfg)
} }
//setting a variable //setting a variable
std::vector<config*>& set_vars = cfg->children["set_variable"]; const config::child_list& set_vars = cfg->get_children("set_variable");
for(std::vector<config*>::iterator var = set_vars.begin(); for(i = set_vars.begin(); i != set_vars.end(); ++i) {
var != set_vars.end(); ++var) {
string_map& vals = (*var)->values; const std::string& name = (**i)["name"];
const std::string& name = vals["name"]; const std::string& value = (**i)["value"];
const std::string& value = vals["value"];
if(value.empty() == false) { if(value.empty() == false) {
state_of_game->variables[name] = value; state_of_game->variables[name] = value;
} }
const std::string& add = vals["add"]; const std::string& add = (**i)["add"];
if(add.empty() == false) { if(add.empty() == false) {
double value = atof(state_of_game->variables[name].c_str()); double value = atof(state_of_game->variables[name].c_str());
value += atof(add.c_str()); value += atof(add.c_str());
@ -331,7 +377,7 @@ void event_handler::handle_event(const queued_event& event_info, config* cfg)
state_of_game->variables[name] = buf; state_of_game->variables[name] = buf;
} }
const std::string& multiply = vals["multiply"]; const std::string& multiply = (**i)["multiply"];
if(multiply.empty() == false) { if(multiply.empty() == false) {
double value = atof(state_of_game->variables[name].c_str()); double value = atof(state_of_game->variables[name].c_str());
value *= atof(multiply.c_str()); value *= atof(multiply.c_str());
@ -342,28 +388,26 @@ void event_handler::handle_event(const queued_event& event_info, config* cfg)
} }
//conditional statements //conditional statements
std::vector<config*>& conditionals = cfg->children["if"]; const config::child_list& conditionals = cfg->get_children("if");
for(std::vector<config*>::iterator cond = conditionals.begin(); for(i = conditionals.begin(); i != conditionals.end(); ++i) {
cond != conditionals.end(); ++cond) {
const std::string type = game_events::conditional_passed( const std::string type = game_events::conditional_passed(
*state_of_game,units,**cond) ? "then":"else"; *state_of_game,units,**i) ? "then":"else";
//if the if statement passed, then execute all 'then' statements, //if the if statement passed, then execute all 'then' statements,
//otherwise execute 'else' statements //otherwise execute 'else' statements
std::vector<config*>& commands = (*cond)->children[type]; const std::vector<config*>& commands = (*i)->get_children(type);
for(std::vector<config*>::iterator cmd = commands.begin(); for(std::vector<config*>::const_iterator cmd = commands.begin();
cmd != commands.end(); ++cmd) { cmd != commands.end(); ++cmd) {
handle_event(event_info,*cmd); handle_event(event_info,*cmd);
} }
} }
//if we are assigning a role to a unit from the available units list //if we are assigning a role to a unit from the available units list
std::vector<config*>& assign_role = cfg->children["role"]; const config::child_list& assign_role = cfg->get_children("role");
for(std::vector<config*>::iterator rl = assign_role.begin(); for(i = assign_role.begin(); i != assign_role.end(); ++i) {
rl != assign_role.end(); ++rl) {
//get a list of the types this unit can be //get a list of the types this unit can be
std::vector<std::string> types = config::split((*rl)->values["type"]); std::vector<std::string> types = config::split((**i)["type"]);
//iterate over all the types, and for each type, try to find //iterate over all the types, and for each type, try to find
//a unit that matches //a unit that matches
@ -375,7 +419,7 @@ void event_handler::handle_event(const queued_event& event_info, config* cfg)
std::map<gamemap::location,unit>::iterator itor; std::map<gamemap::location,unit>::iterator itor;
for(itor = units->begin(); itor != units->end(); ++itor) { for(itor = units->begin(); itor != units->end(); ++itor) {
if(itor->second.matches_filter(cfg)) { if(itor->second.matches_filter(cfg)) {
itor->second.assign_role((*rl)->values["role"]); itor->second.assign_role((**i)["role"]);
break; break;
} }
} }
@ -388,7 +432,7 @@ void event_handler::handle_event(const queued_event& event_info, config* cfg)
for(ui = state_of_game->available_units.begin(); for(ui = state_of_game->available_units.begin();
ui != state_of_game->available_units.end(); ++ui) { ui != state_of_game->available_units.end(); ++ui) {
if(ui->matches_filter(cfg)) { if(ui->matches_filter(cfg)) {
ui->assign_role((*rl)->values["role"]); ui->assign_role((**i)["role"]);
break; break;
} }
} }
@ -404,10 +448,9 @@ void event_handler::handle_event(const queued_event& event_info, config* cfg)
break; break;
} }
std::vector<config*>& remove_overlays = cfg->children["removeitem"]; const config::child_list& remove_overlays = cfg->get_children("removeitem");
for(std::vector<config*>::iterator rm = remove_overlays.begin(); for(i = remove_overlays.begin(); i != remove_overlays.end(); ++i) {
rm != remove_overlays.end(); ++rm) { gamemap::location loc(**i);
gamemap::location loc(**rm);
if(!loc.valid()) { if(!loc.valid()) {
loc = event_info.loc1; loc = event_info.loc1;
} }
@ -416,25 +459,23 @@ void event_handler::handle_event(const queued_event& event_info, config* cfg)
} }
//hiding units //hiding units
std::vector<config*>& hide = cfg->children["hide_unit"]; const config::child_list& hide = cfg->get_children("hide_unit");
for(std::vector<config*>::iterator hd = hide.begin(); for(i = hide.begin(); i != hide.end(); ++i) {
hd != hide.end(); ++hd) { const gamemap::location loc(**i);
const gamemap::location loc(**hd);
screen->hide_unit(loc); screen->hide_unit(loc);
screen->draw_tile(loc.x,loc.y); screen->draw_tile(loc.x,loc.y);
} }
if(cfg->children["unhide_unit"].empty() == false) { if(cfg->child("unhide_unit") != NULL) {
const gamemap::location loc = screen->hide_unit(gamemap::location()); const gamemap::location loc = screen->hide_unit(gamemap::location());
screen->draw_tile(loc.x,loc.y); screen->draw_tile(loc.x,loc.y);
} }
//adding new items //adding new items
std::vector<config*>& add_overlays = cfg->children["item"]; const config::child_list& add_overlays = cfg->get_children("item");
for(std::vector<config*>::iterator ni = add_overlays.begin(); for(i = add_overlays.begin(); i != add_overlays.end(); ++i) {
ni != add_overlays.end(); ++ni) { gamemap::location loc(**i);
gamemap::location loc(**ni); const std::string& img = (**i)["image"];
const std::string& img = (*ni)->values["image"];
if(!img.empty()) { if(!img.empty()) {
screen->add_overlay(loc,img); screen->add_overlay(loc,img);
screen->draw_tile(loc.x,loc.y); screen->draw_tile(loc.x,loc.y);
@ -442,13 +483,12 @@ void event_handler::handle_event(const queued_event& event_info, config* cfg)
} }
//changing the terrain //changing the terrain
std::vector<config*>& terrain_changes = cfg->children["terrain"]; const config::child_list& terrain_changes = cfg->get_children("terrain");
for(std::vector<config*>::iterator tc = terrain_changes.begin(); for(i = terrain_changes.begin(); i != terrain_changes.end(); ++i) {
tc != terrain_changes.end(); ++tc) { const std::vector<gamemap::location> locs = multiple_locs(**i);
const std::vector<gamemap::location> locs = multiple_locs(**tc);
for(std::vector<gamemap::location>::const_iterator loc = locs.begin(); loc != locs.end(); ++loc) { for(std::vector<gamemap::location>::const_iterator loc = locs.begin(); loc != locs.end(); ++loc) {
const std::string& terrain_type = (**tc)["letter"]; const std::string& terrain_type = (**i)["letter"];
if(terrain_type.size() > 0) { if(terrain_type.size() > 0) {
game_map->set_terrain(*loc,terrain_type[0]); game_map->set_terrain(*loc,terrain_type[0]);
screen->recalculate_minimap(); screen->recalculate_minimap();
@ -458,11 +498,10 @@ void event_handler::handle_event(const queued_event& event_info, config* cfg)
} }
//if we should spawn a new unit on the map somewhere //if we should spawn a new unit on the map somewhere
std::vector<config*>& new_units = cfg->children["unit"]; const config::child_list& new_units = cfg->get_children("unit");
for(std::vector<config*>::iterator ui = new_units.begin(); for(i = new_units.begin(); i != new_units.end(); ++i) {
ui != new_units.end(); ++ui) { unit new_unit(*game_data_ptr,**i);
unit new_unit(*game_data_ptr,**ui); gamemap::location loc(**i);
gamemap::location loc(**ui);
if(game_map->on_board(loc)) { if(game_map->on_board(loc)) {
loc = find_vacant_tile(*game_map,*units,loc); loc = find_vacant_tile(*game_map,*units,loc);
@ -474,32 +513,28 @@ void event_handler::handle_event(const queued_event& event_info, config* cfg)
} }
//if we should recall units that match a certain description //if we should recall units that match a certain description
std::vector<config*>& recalls = cfg->children["recall"]; const config::child_list& recalls = cfg->get_children("recall");
for(std::vector<config*>::iterator ir = recalls.begin(); for(i = recalls.begin(); i != recalls.end(); ++i) {
ir != recalls.end(); ++ir) {
std::vector<unit>& avail = state_of_game->available_units; std::vector<unit>& avail = state_of_game->available_units;
for(std::vector<unit>::iterator u = avail.begin(); for(std::vector<unit>::iterator u = avail.begin(); u != avail.end(); ++u) {
u != avail.end(); ++u) { if(u->matches_filter(**i)) {
if(u->matches_filter(**ir)) { recruit_unit(*game_map,1,*units,*u,gamemap::location(),screen,false);
recruit_unit(*game_map,1,*units,*u,gamemap::location(),
screen,false);
avail.erase(u); avail.erase(u);
break; break;
} }
} }
} }
std::vector<config*>& objects = cfg->children["object"]; const config::child_list& objects = cfg->get_children("object");
for(std::vector<config*>::iterator obj = objects.begin(); for(i = objects.begin(); i != objects.end(); ++i) {
obj != objects.end(); ++obj) { const config& values = **i;
string_map& values = (*obj)->values;
//if this item has already been used
if(values["used"].empty() == false)
continue;
const std::string& id = values["id"]; const std::string& id = values["id"];
//if this item has already been used
if(used_items.count(id))
continue;
const std::string image = values["image"]; const std::string image = values["image"];
std::string caption = values["name"]; std::string caption = values["name"];
@ -507,15 +542,14 @@ void event_handler::handle_event(const queued_event& event_info, config* cfg)
if(caption_lang.empty() == false) if(caption_lang.empty() == false)
caption = caption_lang; caption = caption_lang;
const std::map<gamemap::location,unit>::iterator u = const std::map<gamemap::location,unit>::iterator u = units->find(event_info.loc1);
units->find(event_info.loc1);
if(u == units->end()) if(u == units->end())
continue; continue;
std::string text; std::string text;
std::vector<config*>& filters = (*obj)->children["filter"]; const config::child_list& filters = (*i)->get_children("filter");
if(filters.empty() || u->second.matches_filter(*filters[0])) { if(filters.empty() || u->second.matches_filter(*filters[0])) {
const std::string& lang = string_table[id]; const std::string& lang = string_table[id];
@ -524,13 +558,13 @@ void event_handler::handle_event(const queued_event& event_info, config* cfg)
else else
text = values["description"]; text = values["description"];
u->second.add_modification("object",**obj); u->second.add_modification("object",**i);
screen->remove_overlay(event_info.loc1); screen->remove_overlay(event_info.loc1);
screen->select_hex(event_info.loc1); screen->select_hex(event_info.loc1);
screen->invalidate_unit(); screen->invalidate_unit();
//mark that this item won't be used again //mark that this item won't be used again
values["used"] = "true"; used_items.insert(id);
} else { } else {
const std::string& lang = string_table[id + "_cannot_use"]; const std::string& lang = string_table[id + "_cannot_use"];
if(!lang.empty()) if(!lang.empty())
@ -551,10 +585,9 @@ void event_handler::handle_event(const queued_event& event_info, config* cfg)
screen->draw(); screen->draw();
} }
std::vector<config*>& messages = cfg->children["message"]; const config::child_list& messages = cfg->get_children("message");
for(std::vector<config*>::iterator msg = messages.begin(); for(i = messages.begin(); i != messages.end(); ++i) {
msg != messages.end(); ++msg) { const config& values = **i;
string_map& values = (*msg)->values;
std::map<gamemap::location,unit>::iterator speaker = units->end(); std::map<gamemap::location,unit>::iterator speaker = units->end();
if(values["speaker"] == "unit") { if(values["speaker"] == "unit") {
@ -564,7 +597,7 @@ void event_handler::handle_event(const queued_event& event_info, config* cfg)
} else if(values["speaker"] != "narrator") { } else if(values["speaker"] != "narrator") {
for(speaker = units->begin(); speaker != units->end(); for(speaker = units->begin(); speaker != units->end();
++speaker){ ++speaker){
if(speaker->second.matches_filter(**msg)) if(speaker->second.matches_filter(**i))
break; break;
} }
@ -575,21 +608,21 @@ void event_handler::handle_event(const queued_event& event_info, config* cfg)
} }
} }
const string_map::const_iterator sfx = values.find("sound"); const std::string& sfx = values["sound"];
if(sfx != values.end()) { if(sfx != "") {
sound::play_sound(sfx->second); sound::play_sound(sfx);
} }
const std::string& id = values["id"]; const std::string& id = values["id"];
std::string image = (*msg)->values["image"]; std::string image = values["image"];
std::string caption; std::string caption;
const std::string& lang_caption = string_table[id + "_caption"]; const std::string& lang_caption = string_table[id + "_caption"];
if(!lang_caption.empty()) if(!lang_caption.empty())
caption = lang_caption; caption = lang_caption;
else else
caption = (*msg)->values["caption"]; caption = values["caption"];
if(speaker != units->end()) { if(speaker != units->end()) {
screen->highlight_hex(speaker->first); screen->highlight_hex(speaker->first);
@ -610,12 +643,12 @@ void event_handler::handle_event(const queued_event& event_info, config* cfg)
std::vector<std::string> options; std::vector<std::string> options;
std::vector<std::vector<config*>*> option_events; std::vector<std::vector<config*>*> option_events;
std::vector<config*>& menu_items = (*msg)->children["option"]; std::cerr << "building menu items...\n";
for(std::vector<config*>::iterator mi = menu_items.begin();
const std::vector<config*>& menu_items = (*i)->get_children("option");
for(std::vector<config*>::const_iterator mi = menu_items.begin();
mi != menu_items.end(); ++mi) { mi != menu_items.end(); ++mi) {
const std::string& lang_msg = string_table[(*mi)->values["id"]]; const std::string& msg = translate_string_default((**mi)["id"],(**mi)["message"]);
const std::string& msg = lang_msg.empty() ?
(*mi)->values["message"] : lang_msg;
options.push_back(msg); options.push_back(msg);
option_events.push_back(&(*mi)->children["command"]); option_events.push_back(&(*mi)->children["command"]);
} }
@ -638,8 +671,11 @@ void event_handler::handle_event(const queued_event& event_info, config* cfg)
throw replay::error(); throw replay::error();
} }
const std::string& val = if(size_t(option_chosen) >= options.size()) {
cfg->children["choose"].front()->values["value"]; option_chosen = 0;
}
const std::string& val = cfg->children["choose"].front()->values["value"];
option_chosen = atol(val.c_str()); option_chosen = atol(val.c_str());
} else if(options.empty() == false) { } else if(options.empty() == false) {
@ -648,40 +684,38 @@ void event_handler::handle_event(const queued_event& event_info, config* cfg)
if(options.empty() == false) { if(options.empty() == false) {
assert(size_t(option_chosen) < menu_items.size()); assert(size_t(option_chosen) < menu_items.size());
std::vector<config*>& events = *option_events[option_chosen]; const std::vector<config*>& events = *option_events[option_chosen];
for(std::vector<config*>::iterator ev = events.begin(); for(std::vector<config*>::const_iterator ev = events.begin();
ev != events.end(); ++ev) { ev != events.end(); ++ev) {
handle_event(event_info,*ev); handle_event(event_info,*ev);
} }
} }
} }
std::vector<config*>& dead_units = cfg->children["kill"]; const config::child_list& dead_units = cfg->get_children("kill");
for(std::vector<config*>::iterator du = dead_units.begin(); for(i = dead_units.begin(); i != dead_units.end(); ++i) {
du != dead_units.end(); ++du) {
for(std::map<gamemap::location,unit>::iterator i = units->begin(); for(std::map<gamemap::location,unit>::iterator un = units->begin();
i != units->end(); ++i) { un != units->end(); ++un) {
while(i->second.matches_filter(**du) && i != units->end()) { while(un != units->end() && un->second.matches_filter(**i)) {
units->erase(i); units->erase(un);
i = units->begin(); un = units->begin();
} }
} }
std::vector<unit>& avail_units = state_of_game->available_units; std::vector<unit>& avail_units = state_of_game->available_units;
for(std::vector<unit>::iterator j = avail_units.begin(); for(std::vector<unit>::iterator j = avail_units.begin();
j != avail_units.end(); ++j) { j != avail_units.end(); ++j) {
while(j->matches_filter(**du) && j != avail_units.end()) { while(j != avail_units.end() && j->matches_filter(**i)) {
j = avail_units.erase(j); j = avail_units.erase(j);
} }
} }
} }
//adding of new events //adding of new events
std::vector<config*>& new_events = cfg->children["event"]; const config::child_list& new_events = cfg->get_children("event");
for(std::vector<config*>::iterator ne = new_events.begin(); for(i = new_events.begin(); i != new_events.end(); ++i) {
ne != new_events.end(); ++ne) { event_handler new_handler(*i);
event_handler new_handler(*ne);
events_map.insert(std::pair<std::string,event_handler>( events_map.insert(std::pair<std::string,event_handler>(
new_handler.name(),new_handler)); new_handler.name(),new_handler));
} }
@ -832,6 +866,8 @@ manager::manager(config& cfg, display& gui_, gamemap& map_,
units = &units_; units = &units_;
state_of_game = &state_of_game_; state_of_game = &state_of_game_;
game_data_ptr = &game_data_; game_data_ptr = &game_data_;
used_items.clear();
} }
manager::~manager() { manager::~manager() {

View file

@ -18,6 +18,7 @@
#include <algorithm> #include <algorithm>
#include <cstdio> #include <cstdio>
#include <iterator>
#include <sstream> #include <sstream>
time_of_day::time_of_day(config& cfg) time_of_day::time_of_day(config& cfg)
@ -117,6 +118,14 @@ game_state read_game(game_data& data, config* cfg)
res.starting_pos = *starts[0]; res.starting_pos = *starts[0];
} }
res.can_recruit.clear();
const std::string& can_recruit_str = (*cfg)["can_recruit"];
if(can_recruit_str != "") {
const std::vector<std::string> can_recruit = config::split(can_recruit_str);
std::copy(can_recruit.begin(),can_recruit.end(),std::inserter(res.can_recruit,res.can_recruit.end()));
}
return res; return res;
} }
@ -151,6 +160,16 @@ void write_game(const game_state& game, config& cfg)
} }
cfg.children["start"].push_back(new config(game.starting_pos)); cfg.children["start"].push_back(new config(game.starting_pos));
std::stringstream can_recruit;
std::copy(game.can_recruit.begin(),game.can_recruit.end(),std::ostream_iterator<std::string>(can_recruit,","));
std::string can_recruit_str = can_recruit.str();
//remove the trailing comma
if(can_recruit_str.size() > 0)
can_recruit_str.resize(can_recruit_str.size()-1);
cfg["can_recruit"] = can_recruit_str;
} }
//a structure for comparing to save_info objects based on their modified time. //a structure for comparing to save_info objects based on their modified time.

View file

@ -88,10 +88,12 @@ struct game_state
std::string campaign_type; //type of the game - campaign, multiplayer etc std::string campaign_type; //type of the game - campaign, multiplayer etc
std::string scenario; //the scenario being played std::string scenario; //the scenario being played
int gold; //amount of gold the player has saved int gold; //amount of gold the player has saved
std::vector<unit> available_units; //units the player has to recall std::vector<unit> available_units; //units the player may recall
std::map<std::string,std::string> variables; //variables that have been set std::map<std::string,std::string> variables; //variables that have been set
std::string difficulty; //the difficulty level the game is being played on. std::string difficulty; //the difficulty level the game is being played on.
std::set<std::string> can_recruit; //units the player has the ability to recruit
//if the game is saved mid-level, we have a series of replay steps to //if the game is saved mid-level, we have a series of replay steps to
//take the game up to the position it was saved at. //take the game up to the position it was saved at.
config replay_data; config replay_data;

View file

@ -36,7 +36,7 @@ const std::string& translate_string(const std::string& str)
const std::string& translate_string_default(const std::string& str, const std::string& default_val) const std::string& translate_string_default(const std::string& str, const std::string& default_val)
{ {
const string_map::const_iterator i = string_table.find(str); const string_map::const_iterator i = string_table.find(str);
if(i != string_table.end()) if(i != string_table.end() && i->second != "")
return i->second; return i->second;
else else
return default_val; return default_val;

View file

@ -64,10 +64,10 @@ gamemap::TERRAIN gamemap::underlying_terrain(TERRAIN terrain) const
} }
} }
gamemap::location::location(config& cfg) : x(-1), y(-1) gamemap::location::location(const config& cfg) : x(-1), y(-1)
{ {
const std::string& xstr = cfg.values["x"]; const std::string& xstr = cfg["x"];
const std::string& ystr = cfg.values["y"]; const std::string& ystr = cfg["y"];
//the co-ordinates in config files will be 1-based, while we //the co-ordinates in config files will be 1-based, while we
//want them as 0-based //want them as 0-based

View file

@ -57,7 +57,7 @@ public:
location() : x(-1), y(-1) {} location() : x(-1), y(-1) {}
location(int x, int y) : x(x), y(y) {} location(int x, int y) : x(x), y(y) {}
location(config& cfg); location(const config& cfg);
bool valid() const { return x >= 0 && y >= 0; } bool valid() const { return x >= 0 && y >= 0; }

View file

@ -25,6 +25,7 @@
#include "tooltips.hpp" #include "tooltips.hpp"
#include <iostream> #include <iostream>
#include <iterator>
LEVEL_RESULT play_level(game_data& gameinfo, config& terrain_config, LEVEL_RESULT play_level(game_data& gameinfo, config& terrain_config,
config* level, CVideo& video, config* level, CVideo& video,
@ -68,26 +69,35 @@ LEVEL_RESULT play_level(game_data& gameinfo, config& terrain_config,
if(gold.empty()) if(gold.empty())
gold = "100"; gold = "100";
const int minimum_gold = 100;
int ngold = ::atoi(gold.c_str()); int ngold = ::atoi(gold.c_str());
if(ui == unit_cfg.begin() && state_of_game.gold >= minimum_gold && if(ui == unit_cfg.begin() && state_of_game.gold >= ngold &&
(*level)["disallow_recall"] != "yes") (*level)["disallow_recall"] != "yes")
ngold = state_of_game.gold; ngold = state_of_game.gold;
const gamemap::location& start_pos = const gamemap::location& start_pos = map.starting_position(new_unit.side());
map.starting_position(new_unit.side());
if(!start_pos.valid()) { if(!start_pos.valid() && new_unit.side() == 1) {
std::stringstream err; throw gamestatus::load_game_failed("No starting position for side 1");
err << "No starting position for side " << new_unit.side();
throw gamestatus::load_game_failed(err.str());
} }
if(start_pos.valid()) {
units.insert(std::pair<gamemap::location,unit>( units.insert(std::pair<gamemap::location,unit>(
map.starting_position(new_unit.side()), new_unit)); map.starting_position(new_unit.side()), new_unit));
}
teams.push_back(team(**ui,ngold)); teams.push_back(team(**ui,ngold));
//if the game state specifies units that can be recruited for the player
//then add them
if(teams.size() == 1 && state_of_game.can_recruit.empty() == false) {
std::copy(state_of_game.can_recruit.begin(),state_of_game.can_recruit.end(),
std::inserter(teams.back().recruits(),teams.back().recruits().end()));
}
if(teams.size() == 1) {
state_of_game.can_recruit = teams.back().recruits();
}
if(first_human_team == -1 && teams.back().is_human()) { if(first_human_team == -1 && teams.back().is_human()) {
first_human_team = teams.size()-1; first_human_team = teams.size()-1;
} }
@ -373,10 +383,6 @@ LEVEL_RESULT play_level(game_data& gameinfo, config& terrain_config,
} catch(end_level_exception&) { } catch(end_level_exception&) {
} }
if((*level)["disallow_recall"] == "yes") {
return VICTORY;
}
//add all the units that survived the scenario //add all the units that survived the scenario
for(std::map<gamemap::location,unit>::iterator un = for(std::map<gamemap::location,unit>::iterator un =
units.begin(); un != units.end(); ++un) { units.begin(); un != units.end(); ++un) {
@ -387,6 +393,10 @@ LEVEL_RESULT play_level(game_data& gameinfo, config& terrain_config,
} }
} }
if((*level)["disallow_recall"] == "yes") {
return VICTORY;
}
const int remaining_gold = teams[0].gold(); const int remaining_gold = teams[0].gold();
const int finishing_bonus_per_turn = const int finishing_bonus_per_turn =
map.towers().size()*game_config::tower_income; map.towers().size()*game_config::tower_income;

View file

@ -613,6 +613,11 @@ void turn_info::show_menu()
menu.push_back(string_table[*items]); menu.push_back(string_table[*items]);
} }
static const std::string create_unit_debug = "Create Unit (debug)";
if(game_config::debug) {
menu.push_back(create_unit_debug);
}
if(un != units_.end()) { if(un != units_.end()) {
menu.push_back(string_table["describe_unit"]); menu.push_back(string_table["describe_unit"]);
@ -631,7 +636,24 @@ void turn_info::show_menu()
menu.pop_back(); menu.pop_back();
} }
if(result == string_table["describe_unit"]) { if(result == create_unit_debug) {
std::vector<std::string> options;
std::vector<unit> unit_choices;
for(game_data::unit_type_map::const_iterator i = gameinfo_.unit_types.begin();
i != gameinfo_.unit_types.end(); ++i) {
options.push_back(i->first);
unit_choices.push_back(unit(&i->second,1,false));
}
const int choice = gui::show_dialog(gui_,NULL,"","Create unit (debug):",
gui::OK_CANCEL,&options,&unit_choices);
if(choice >= 0 && choice < unit_choices.size()) {
units_.erase(last_hex_);
units_.insert(std::pair<gamemap::location,unit>(last_hex_,unit_choices[choice]));
gui_.invalidate(last_hex_);
gui_.invalidate_unit();
}
} else if(result == string_table["describe_unit"]) {
unit_description(); unit_description();
} else if(result == string_table["rename_unit"]) { } else if(result == string_table["rename_unit"]) {
rename_unit(); rename_unit();
@ -1003,7 +1025,7 @@ void turn_info::rename_unit()
void turn_info::save_game() void turn_info::save_game()
{ {
std::stringstream stream; std::stringstream stream;
stream << translate_string(state_of_game_.scenario) << " " << string_table["turn"] stream << state_of_game_.label << " " << string_table["turn"]
<< " " << status_.turn(); << " " << status_.turn();
std::string label = stream.str(); std::string label = stream.str();
@ -1189,8 +1211,12 @@ void turn_info::recall()
<< string_table["level"] << ": " << string_table["level"] << ": "
<< unit->type().level() << "," << unit->type().level() << ","
<< string_table["xp"] << ": " << string_table["xp"] << ": "
<< unit->experience() << "/" << unit->experience() << "/";
<< unit->max_experience();
if(unit->type().advances_to().empty())
option << "-";
else
option << unit->max_experience();
options.push_back(option.str()); options.push_back(option.str());
} }

View file

@ -58,6 +58,16 @@ int get_random()
return random_generator->get_random(); return random_generator->get_random();
} }
const config* get_random_results()
{
return random_generator->get_random_results();
}
void set_random_results(const config& cfg)
{
random_generator->set_random_results(cfg);
}
replay::replay() : pos_(0), current_(NULL), skip_(0) replay::replay() : pos_(0), current_(NULL), skip_(0)
{} {}
@ -287,6 +297,19 @@ int replay::get_random()
} }
} }
const config* replay::get_random_results() const
{
assert(current_ != NULL);
return current_->child("results");
}
void replay::set_random_results(const config& cfg)
{
assert(current_ != NULL);
current_->children["results"].clear();
current_->children["results"].push_back(new config(cfg));
}
void replay::start_replay() void replay::start_replay()
{ {
pos_ = 0; pos_ = 0;
@ -537,7 +560,9 @@ bool do_replay(display& disp, const gamemap& map, const game_data& gameinfo,
std::map<gamemap::location,unit>::const_iterator tgt = units.find(dst); std::map<gamemap::location,unit>::const_iterator tgt = units.find(dst);
if(tgt == units.end()) { if(tgt == units.end()) {
std::cerr << "unfound defender for attack\n"; std::cerr << "unfound defender for attack: "
<< (src.x+1) << "," << (src.y+1) << " -> "
<< (dst.x+1) << "," << (dst.y+1) << "\n";
throw replay::error(); throw replay::error();
} }

View file

@ -19,6 +19,9 @@
int get_random(); int get_random();
const config* get_random_results();
void set_random_results(const config& cfg);
class replay class replay
{ {
public: public:
@ -50,6 +53,8 @@ public:
void undo(); void undo();
int get_random(); int get_random();
const config* get_random_results() const;
void set_random_results(const config& cfg);
void start_replay(); void start_replay();
config* get_next_action(); config* get_next_action();

View file

@ -379,7 +379,7 @@ int show_dialog(display& disp, SDL_Surface* image,
text_widget_height + check_button_height; text_widget_height + check_button_height;
if(total_width > scr->w - 100 || total_height > scr->h - 100) if(total_width > scr->w - 100 || total_height > scr->h - 100)
return false; return 0;
int xloc = scr->w/2 - total_width/2; int xloc = scr->w/2 - total_width/2;
int yloc = scr->h/2 - total_height/2; int yloc = scr->h/2 - total_height/2;
@ -399,9 +399,12 @@ int show_dialog(display& disp, SDL_Surface* image,
//make sure that the dialog doesn't overlap the right part of the screen //make sure that the dialog doesn't overlap the right part of the screen
if(xloc + total_width+border_size >= disp.mapx()-1) { if(xloc + total_width+border_size >= disp.mapx()-1) {
std::cerr << "in if...\n";
xloc = disp.mapx()-(total_width+border_size+2); xloc = disp.mapx()-(total_width+border_size+2);
if(xloc < 0) if(xloc < 0) {
return -1; std::cerr << "dialog is too large to fit on-screen!\n";
return 0;
}
} }
const int button_hpadding = total_width - button_widths; const int button_hpadding = total_width - button_widths;

View file

@ -157,6 +157,11 @@ const std::set<std::string>& team::recruits() const
return info_.can_recruit; return info_.can_recruit;
} }
std::set<std::string>& team::recruits()
{
return info_.can_recruit;
}
const std::vector<std::string>& team::recruitment_pattern() const const std::vector<std::string>& team::recruitment_pattern() const
{ {
return info_.recruitment_pattern; return info_.recruitment_pattern;

View file

@ -69,6 +69,7 @@ public:
void spend_gold(int amount); void spend_gold(int amount);
const std::set<std::string>& recruits() const; const std::set<std::string>& recruits() const;
std::set<std::string>& recruits();
const std::vector<std::string>& recruitment_pattern() const; const std::vector<std::string>& recruitment_pattern() const;
const std::string& name() const; const std::string& name() const;