diff --git a/changelog b/changelog index 5f120e50673..a01f61e33a8 100644 --- a/changelog +++ b/changelog @@ -1,9 +1,9 @@ Version 0.6: * radical storyline changes, this breaks saves from older versions * fog of war - * support for multiple campaigns * enemy units do not vanish anymore when enemy leader is killed * new scenarios for 'Heir to the Throne' (Konrad's Tale): + * Isle of the Damned * Northern Winter * The Lost General * Hasty Alliance @@ -17,6 +17,7 @@ Version 0.6: * Dwarven Doors * Mountain Pass * Valley of Death + * support for multiple campaigns * new campaign started: 'Hordes of the Undead' * multiplayer improvements: * show minimap when selecting map for new game @@ -47,10 +48,12 @@ Version 0.6: * Elvish Scout * Pikeman * 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 cost of Mage * 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 'Red Mage' to neutral alignment * removed 'Elvish Outrider' as evolution from Horseman @@ -61,8 +64,8 @@ Version 0.6: * 'Blood Bat' unit description clarified * Halberdier changed to 3rd level unit * Spearman now advances to Pikeman - * Fire resistance added to 'Red Mage' branch units - * Holy resistance added to Holy units. + * Increased fire resistance for 'Red Mage' branch units + * Increased holy resistance made higher for Holy units. * auto-naming (currently elves and humans only) of units and renaming of units * units now have races defined in cfg-files * 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 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 problem where 'goto numbers' can overwrite part of the right panel * footsteps disappear as you walk over them * added engine support for weapons that can reach multiple hexes * added some utility macros to WML @@ -122,6 +126,7 @@ Version 0.6: * fixed tool tips to work again * fix hitpoint bar problem on MacOSX * 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 * added some comments to code diff --git a/configure b/configure index 47de1da1ee1..ba6f8fc6bf6 100755 --- a/configure +++ b/configure @@ -1337,7 +1337,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu PACKAGE=wesnoth MAJOR_VERSION="0" -MINOR_VERSION="6RC2" +MINOR_VERSION="6RC3" MICRO_VERSION="" if test "x$MICRO_VERSION" = "x"; then diff --git a/configure.ac b/configure.ac index d6537c66b06..e4bde1a4184 100644 --- a/configure.ac +++ b/configure.ac @@ -6,7 +6,7 @@ AC_INIT(wesnoth, 0.5, davidnwhite@optusnet.com.au, Battle for Wesnoth) AC_REVISION($Version: 0.5$) PACKAGE=wesnoth MAJOR_VERSION="0" -MINOR_VERSION="6RC2" +MINOR_VERSION="6RC3" MICRO_VERSION="" if test "x$MICRO_VERSION" = "x"; then diff --git a/data/scenario-test.cfg b/data/scenario-test.cfg index 20d7e30d9ec..4a51f9c08f5 100644 --- a/data/scenario-test.cfg +++ b/data/scenario-test.cfg @@ -14,7 +14,7 @@ {STORM_TRIDENT 10 5} [side] - type=Commander + type=Fighter description=Konrad side=1 canrecruit=1 diff --git a/data/scenarios/A_Choice_Must_Be_Made.cfg b/data/scenarios/A_Choice_Must_Be_Made.cfg index 3fd52afcd26..2c8a073555b 100644 --- a/data/scenarios/A_Choice_Must_Be_Made.cfg +++ b/data/scenarios/A_Choice_Must_Be_Made.cfg @@ -25,7 +25,6 @@ Defeat side=1 canrecruit=1 controller=human - recruit=Elvish Scout,Elvish Fighter,Elvish Archer,Horseman,Mage,Elvish Shaman,Thief,Merman enemy=2,3 [/side] diff --git a/data/scenarios/Bay_of_Pearls.cfg b/data/scenarios/Bay_of_Pearls.cfg index 863efec05ec..06075d276a2 100644 --- a/data/scenarios/Bay_of_Pearls.cfg +++ b/data/scenarios/Bay_of_Pearls.cfg @@ -19,6 +19,7 @@ objectives=" Victory: @Defeat both enemy leaders +@Defeat at least one enemy leader, and resist until time expires Defeat: #Death of Konrad #Turns run out" @@ -499,12 +500,18 @@ The main cage where they keep most of the mermen is in the south-east!" [/message] [/event] - [event] - name=victory + #the ship they came on. + [item] + x=30 + y=7 + image=galleon.png + [/item] + +#define BAY_OF_PEARLS_VICTORY [message] id=msg3_16 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] [role] type=Merman Lord,Merman @@ -545,7 +552,7 @@ The main cage where they keep most of the mermen is in the south-east!" [message] id=msg3_22 description=Konrad - message=Oh no! What should we do? + message=Oh no! What shall we do? [/message] [message] @@ -573,7 +580,7 @@ The main cage where they keep most of the mermen is in the south-east!" [/message] [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] [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] [message] - id=msg3_29 + id=msg3_29a description=Konrad - message=Very well. Until we meet again, my dear friend! + message=Very well. But how do I get to Elensefar? [/message] [message] - id=msg3_30 + id=msg3_30a 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] + [/command] + [command] + [kill] + description=Delfador + [/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] - [kill] - description=Delfador - [/kill] +#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] [/scenario] diff --git a/data/scenarios/Dwarven_Doors.cfg b/data/scenarios/Dwarven_Doors.cfg index a4236d819e1..c6d1600f3a6 100644 --- a/data/scenarios/Dwarven_Doors.cfg +++ b/data/scenarios/Dwarven_Doors.cfg @@ -17,11 +17,7 @@ [bigmap] image=misc/map.png - [dot] - type=cross - x=187 - y=187 - [/dot] + {CROSS 378 140} [/bigmap] objectives=" @@ -74,7 +70,6 @@ Defeat: side=1 canrecruit=1 controller=human - recruit=Elvish Scout,Elvish Fighter,Elvish Archer,Horseman,Mage,Elvish Shaman,Merman,Thief,Gryphon Rider enemy=2,3,4 [/side] diff --git a/data/scenarios/Elves_Besieged.cfg b/data/scenarios/Elves_Besieged.cfg index 3e0134d878c..a58e9cced2e 100644 --- a/data/scenarios/Elves_Besieged.cfg +++ b/data/scenarios/Elves_Besieged.cfg @@ -39,7 +39,7 @@ Defeat: [/bigmap] [side] - type=Commander + type=Fighter description=Konrad side=1 canrecruit=1 @@ -62,11 +62,11 @@ Defeat: [target] description=Delfador value=100 - [end] + [/target] [target] description=Konrad value=100 - [end] + [/target] #enddef #else #define HIGH_PRIORITY_TARGETS @@ -205,7 +205,7 @@ Defeat: id=msg1_9hard 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!" - [end] + [/message] #else [message] id=msg1_9 diff --git a/data/scenarios/Ford_of_Abez.cfg b/data/scenarios/Ford_of_Abez.cfg index 4b4fe00d0a8..edb9db726c3 100644 --- a/data/scenarios/Ford_of_Abez.cfg +++ b/data/scenarios/Ford_of_Abez.cfg @@ -17,11 +17,10 @@ [bigmap] image=misc/map.png - [dot] - type=cross - x=187 - y=187 - [/dot] + {DOT 305 202} + {DOT 313 195} + {DOT 321 188} + {CROSS 321 182} [/bigmap] objectives=" @@ -38,7 +37,7 @@ Defeat: side=1 canrecruit=1 controller=human - recruit=Elvish Scout,Elvish Fighter,Elvish Archer,Horseman,Mage,Elvish Shaman,Merman,Thief,Gryphon Rider + recruit=Gryphon Rider enemy=2,3 [/side] diff --git a/data/scenarios/Gryphon_Mountain.cfg b/data/scenarios/Gryphon_Mountain.cfg index f1867f8596c..630289a2c54 100644 --- a/data/scenarios/Gryphon_Mountain.cfg +++ b/data/scenarios/Gryphon_Mountain.cfg @@ -26,6 +26,10 @@ Defeat: [bigmap] image=misc/map.png [dot] + {DOT 262 225} + {DOT 272 214} + {DOT 288 207} + {CROSS 298 208} type=cross x=187 y=187 @@ -63,7 +67,6 @@ Defeat: side=1 canrecruit=1 controller=human - recruit=Elvish Scout,Elvish Fighter,Elvish Archer,Horseman,Mage,Merman,Thief enemy=2,3 [/side] diff --git a/data/scenarios/Hasty_Alliance.cfg b/data/scenarios/Hasty_Alliance.cfg index ed8004e209d..6204c027e8b 100644 --- a/data/scenarios/Hasty_Alliance.cfg +++ b/data/scenarios/Hasty_Alliance.cfg @@ -34,7 +34,6 @@ Defeat: side=1 canrecruit=1 controller=human - recruit=Elvish Scout,Elvish Fighter,Elvish Archer,Horseman,Mage,Elvish Shaman,Merman,Thief,Gryphon Rider,Dwarvish Fighter,Dwarvish Thunderer enemy=3 shroud=yes [/side] diff --git a/data/scenarios/Isle_of_the_Damned.cfg b/data/scenarios/Isle_of_the_Damned.cfg new file mode 100644 index 00000000000..551f1da7414 --- /dev/null +++ b/data/scenarios/Isle_of_the_Damned.cfg @@ -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] diff --git a/data/scenarios/Mountain_Pass.cfg b/data/scenarios/Mountain_Pass.cfg index 06ec6dd8ef0..eeb6f561311 100644 --- a/data/scenarios/Mountain_Pass.cfg +++ b/data/scenarios/Mountain_Pass.cfg @@ -17,11 +17,9 @@ [bigmap] image=misc/map.png - [dot] - type=cross - x=187 - y=187 - [/dot] + {DOT 354 167} + {DOT 355 157} + {CROSS 356 147} [/bigmap] objectives=" @@ -38,7 +36,6 @@ Defeat: side=1 canrecruit=1 controller=human - recruit=Elvish Scout,Elvish Fighter,Elvish Archer,Horseman,Mage,Elvish Shaman,Merman,Thief,Gryphon Rider enemy=2,3 fog=yes [/side] @@ -61,15 +58,8 @@ Defeat: recruitment_pattern=fighter villages_per_scout=0 -#ifdef EASY - gold=150 -#endif -#ifdef NORMAL - gold=200 -#endif -#ifdef HARD - gold=280 -#endif + {GOLD 150 200 280} + enemy=1 [/side] @@ -87,18 +77,8 @@ Defeat: #endif recruitment_pattern=fighter,scout,scout,mixed fighter villages_per_scout=0 -#ifdef EASY - gold=200 - income=20 -#endif -#ifdef NORMAL - gold=250 - income=30 -#endif -#ifdef HARD - gold=350 - income=50 -#endif + {GOLD 150 250 350} + {INCOME 15 30 50} enemy=1 village_value=0 leader_value=10 diff --git a/data/scenarios/Muff_Malal_Peninsula.cfg b/data/scenarios/Muff_Malal_Peninsula.cfg index 7d7c6337fea..a1990d9a2f1 100644 --- a/data/scenarios/Muff_Malal_Peninsula.cfg +++ b/data/scenarios/Muff_Malal_Peninsula.cfg @@ -27,7 +27,7 @@ Defeat: image=misc/map.png {DOT 164 348} {DOT 158 340} - {DOT 142 355} + {DOT 142 338} {DOT 127 340} {CROSS 122 331} [/bigmap] @@ -224,6 +224,11 @@ Defeat: [kill] description=Moremirmu [/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] name=die diff --git a/data/scenarios/Northern_Winter.cfg b/data/scenarios/Northern_Winter.cfg index caa0f462024..2208fe1f832 100644 --- a/data/scenarios/Northern_Winter.cfg +++ b/data/scenarios/Northern_Winter.cfg @@ -26,11 +26,9 @@ Defeat: [bigmap] image=misc/map.png - [dot] - type=cross - x=77 - y=235 - [/dot] + {DOT 336 180} + {DOT 344 174} + {CROSS 354 167} [/bigmap] [side] @@ -41,7 +39,6 @@ Defeat: experience=0 side=1 canrecruit=1 - recruit=Elvish Scout,Elvish Fighter,Elvish Archer,Horseman,Mage,Elvish Shaman,Merman,Thief,Gryphon Rider enemy=2,3 controller=human [/side] diff --git a/data/scenarios/Plunging_Into_the_Darkness.cfg b/data/scenarios/Plunging_Into_the_Darkness.cfg index 332c40c3fdd..bfc1649a7e7 100644 --- a/data/scenarios/Plunging_Into_the_Darkness.cfg +++ b/data/scenarios/Plunging_Into_the_Darkness.cfg @@ -33,7 +33,6 @@ Defeat side=1 canrecruit=1 controller=human - recruit=Elvish Scout,Elvish Fighter,Elvish Archer,Horseman,Mage,Elvish Shaman,Merman,Thief,Gryphon Rider enemy=2 shroud=yes [/side] diff --git a/data/scenarios/Princess_of_Wesnoth.cfg b/data/scenarios/Princess_of_Wesnoth.cfg index af0d61a2fc0..e875c9169a2 100644 --- a/data/scenarios/Princess_of_Wesnoth.cfg +++ b/data/scenarios/Princess_of_Wesnoth.cfg @@ -53,8 +53,7 @@ Defeat: side=1 canrecruit=1 controller=human - recruit=Elvish Scout,Elvish Fighter,Elvish Archer,Horseman,Mage,Elvish Shaman,Merman,Thief - enemy=2 + enemy=2 [/side] [side] diff --git a/data/scenarios/Sceptre.cfg b/data/scenarios/Sceptre.cfg index ea4d9160923..ebd45736d3d 100644 --- a/data/scenarios/Sceptre.cfg +++ b/data/scenarios/Sceptre.cfg @@ -34,7 +34,6 @@ Defeat: side=1 canrecruit=1 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 shroud=yes [/side] @@ -48,20 +47,8 @@ Defeat: recruit=Goblin Knight,Wolf Rider,Troll,Orcish Warrior,Orcish Crossbow enemy=1 -#ifdef EASY - gold=300 - income=10 -#endif - -#ifdef MEDIUM - gold=400 - income=20 -#endif - -#ifdef HARD - gold=550 - income=30 -#endif + {GOLD 150 300 400} + {INCOME 5 10 20} [/side] [side] type=Troll Warrior @@ -72,21 +59,8 @@ Defeat: recruitment_pattern=fighter recruit=Troll,Troll Warrior,Ogre enemy=1 - -#ifdef EASY - gold=300 - income=10 -#endif - -#ifdef MEDIUM - gold=400 - income=20 -#endif - -#ifdef HARD - gold=550 - income=30 -#endif + {GOLD 150 300 400} + {INCOME 5 10 20} [/side] [side] @@ -99,20 +73,8 @@ Defeat: recruit=Troll,Troll Warrior,Ogre,Goblin Knight,Wolf Rider,Troll Whelp enemy=1 -#ifdef EASY - gold=200 - income=10 -#endif - -#ifdef MEDIUM - gold=300 - income=20 -#endif - -#ifdef HARD - gold=450 - income=30 -#endif + {GOLD 150 230 350} + {INCOME 5 10 20} [/side] [side] @@ -124,21 +86,8 @@ Defeat: recruitment_pattern=fighter,fighter,scout recruit=Troll,Troll Warrior,Ogre,Goblin Knight,Wolf Rider,Troll Whelp enemy=1 - -#ifdef EASY - gold=200 - income=15 -#endif - -#ifdef MEDIUM - gold=300 - income=20 -#endif - -#ifdef HARD - gold=450 - income=30 -#endif + {GOLD 150 230 350} + {INCOME 5 10 20} [/side] #dummy enemy that forces finding the Sceptre diff --git a/data/scenarios/Siege_to_Elefansar.cfg b/data/scenarios/Siege_to_Elefansar.cfg index 84c1543ce9a..db718864625 100644 --- a/data/scenarios/Siege_to_Elefansar.cfg +++ b/data/scenarios/Siege_to_Elefansar.cfg @@ -123,7 +123,7 @@ Defeat: [/message] [message] 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] [message] @@ -139,7 +139,7 @@ Defeat: [/event] [event] - name=turn 6 + name=turn 5 [unit] description=Reglok type=Thief @@ -178,7 +178,7 @@ Defeat: [/message] [message] id=msg5_10 - description=Advisor + role=Advisor message=Thieves hmmm? Who says we can trust such as you? [/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] [message] - id=msg5_12 + id=msg5_12a 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] [/event] diff --git a/data/scenarios/Snow_Plains.cfg b/data/scenarios/Snow_Plains.cfg index 5fe7b7a58a5..bb5f75b2bfe 100644 --- a/data/scenarios/Snow_Plains.cfg +++ b/data/scenarios/Snow_Plains.cfg @@ -26,7 +26,6 @@ Defeat side=1 canrecruit=1 controller=human - recruit=Elvish Scout,Elvish Fighter,Elvish Archer,Horseman,Mage,Elvish Shaman,Thief,Merman enemy=2,3 [/side] diff --git a/data/scenarios/Swamp_Of_Dread.cfg b/data/scenarios/Swamp_Of_Dread.cfg index e275bfd2139..6dd26594c8f 100644 --- a/data/scenarios/Swamp_Of_Dread.cfg +++ b/data/scenarios/Swamp_Of_Dread.cfg @@ -27,7 +27,6 @@ Defeat canrecruit=1 controller=human hitpoints=80 - recruit=Elvish Scout,Elvish Fighter,Elvish Archer,Horseman,Mage,Elvish Shaman,Thief,Merman enemy=2,3,4,5,6 [/side] diff --git a/data/scenarios/The_Lost_General.cfg b/data/scenarios/The_Lost_General.cfg index d92084a9775..334f33343c1 100644 --- a/data/scenarios/The_Lost_General.cfg +++ b/data/scenarios/The_Lost_General.cfg @@ -33,7 +33,7 @@ Defeat: side=1 canrecruit=1 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 shroud=yes [/side] diff --git a/data/scenarios/Valley_of_Death.cfg b/data/scenarios/Valley_of_Death.cfg index f930dc72ff4..dbcafbc55c1 100644 --- a/data/scenarios/Valley_of_Death.cfg +++ b/data/scenarios/Valley_of_Death.cfg @@ -25,11 +25,10 @@ Defeat: [bigmap] image=misc/map.png - [dot] - type=cross - x=207 - y=147 - [/dot] + {DOT 250 255} + {DOT 251 246} + {DOT 253 239} + {CROSS 253 231} [/bigmap] [side] @@ -38,7 +37,6 @@ Defeat: side=1 canrecruit=1 controller=human - recruit=Elvish Scout,Elvish Fighter,Elvish Archer,Horseman,Mage,Elvish Shaman,Merman,Thief recruitment_pattern=scout,fighter,archer aggression=-0.5 village_value=1.0 diff --git a/data/tutorial.cfg b/data/tutorial.cfg index 867254656fd..e666eeded53 100644 --- a/data/tutorial.cfg +++ b/data/tutorial.cfg @@ -20,7 +20,7 @@ Defeat: [side] race=Elves - type=Commander + type=Fighter description=Konrad experience=0 side=1 diff --git a/data/units/Commander.cfg b/data/units/Commander.cfg index 21d082c95e9..06916b9b42f 100644 --- a/data/units/Commander.cfg +++ b/data/units/Commander.cfg @@ -7,7 +7,7 @@ hitpoints=45 ability=leadership movement_type=smallfoot movement=6 -experience=80 +experience=60 level=2 alignment=lawful advanceto=Lord @@ -29,15 +29,15 @@ get_hit_sound=groan.wav name=sword type=blade range=short - damage=6 + damage=8 number=4 [frame] - begin=-350 - end=-300 + begin=-250 + end=-200 image=konrad-commander.png [/frame] [frame] - begin=-300 + begin=-200 end=-100 image="konrad-commander-attack1.png" [/frame] @@ -66,7 +66,7 @@ get_hit_sound=groan.wav name=bow type=pierce range=long - damage=3 + damage=6 number=3 [sound] time=-100 diff --git a/data/units/Fighter.cfg b/data/units/Fighter.cfg new file mode 100644 index 00000000000..42cbd406223 --- /dev/null +++ b/data/units/Fighter.cfg @@ -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] diff --git a/data/units/Goblin_Pillager.cfg b/data/units/Goblin_Pillager.cfg index f3bc2ddc483..a1934dc81ea 100644 --- a/data/units/Goblin_Pillager.cfg +++ b/data/units/Goblin_Pillager.cfg @@ -12,7 +12,7 @@ alignment=chaotic advanceto=null cost=22 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 [attack] name=torch diff --git a/data/units/Lord.cfg b/data/units/Lord.cfg index 18e15154cc7..5061a2798b1 100644 --- a/data/units/Lord.cfg +++ b/data/units/Lord.cfg @@ -3,7 +3,7 @@ name=Lord race=human image=konrad-lord.png profile=misc/konrad.png -hitpoints=65 +hitpoints=68 ability=leadership movement_type=smallfoot movement=6 @@ -19,7 +19,7 @@ get_hit_sound=groan.wav name=sword type=blade range=short - damage=11 + damage=14 number=4 [/attack] [attack] diff --git a/data/units/Troll.cfg b/data/units/Troll.cfg index f38d0f77b3e..60ceab9094e 100644 --- a/data/units/Troll.cfg +++ b/data/units/Troll.cfg @@ -20,5 +20,10 @@ usage=fighter range=short damage=14 number=2 + [frame] + begin=-100 + end=100 + image=troll-grunt-attack.png + [/frame] [/attack] [/unit] diff --git a/images/troll-grunt-attack.png b/images/troll-grunt-attack.png new file mode 100644 index 00000000000..dedc6a0054a Binary files /dev/null and b/images/troll-grunt-attack.png differ diff --git a/src/actions.cpp b/src/actions.cpp index a481299191c..ffa295a84c4 100644 --- a/src/actions.cpp +++ b/src/actions.cpp @@ -341,15 +341,72 @@ void attack(display& gui, const gamemap& map, while(stats.nattacks > 0 || stats.ndefends > 0) { if(stats.nattacks > 0) { - const bool hits = (get_random()%100) < stats.chance_to_hit_defender; - const bool dies = gui.unit_attack(attacker,defender, - hits ? stats.damage_defender_takes : 0, - a->second.attacks()[attack_with]); + const int ran_num = get_random(); + 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, + 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) { attackerxp = 8*d->second.type().level(); if(d->second.type().level() == 0) attackerxp = 4; + a->second.get_experience(attackerxp); + attackerxp = 0; defenderxp = 0; gamemap::location loc = d->first; @@ -397,16 +454,72 @@ void attack(display& gui, const gamemap& map, } if(stats.ndefends > 0) { - const bool hits = (get_random()%100) < stats.chance_to_hit_attacker; - const bool dies = gui.unit_attack(defender,attacker, + const int ran_num = get_random(); + 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, 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) { defenderxp = 8*a->second.type().level(); if(a->second.type().level() == 0) defenderxp = 4; + d->second.get_experience(defenderxp); + defenderxp = 0; attackerxp = 0; gamemap::location loc = a->first; @@ -742,6 +855,10 @@ void check_victory(std::map& units, } if(found_enemies == false) { + if(found_human) { + game_events::fire("enemies defeated"); + } + throw end_level_exception(found_human ? VICTORY : DEFEAT); } diff --git a/src/config.cpp b/src/config.cpp index 7036596d4e8..856018bb226 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -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) { const child_map::const_iterator i = children.find(key); diff --git a/src/config.hpp b/src/config.hpp index 5b8593ec7b5..df122837ebb 100644 --- a/src/config.hpp +++ b/src/config.hpp @@ -107,6 +107,8 @@ struct config child_itors child_range(const std::string& key); 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); const config* child(const std::string& key) const; diff --git a/src/display.cpp b/src/display.cpp index febdf40d600..fd125fe50d2 100644 --- a/src/display.cpp +++ b/src/display.cpp @@ -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); - 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) { const SDL_Color& colour = font::get_side_colour(it->second.side()); 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); 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'); str[0] = '0' + route_.move_left + 1; 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 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); } } diff --git a/src/game.cpp b/src/game.cpp index 20c7996e28a..e4dfb9979e2 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -64,7 +64,7 @@ LEVEL_RESULT play_game(display& disp, game_state& state, config& game_config, try { LEVEL_RESULT res = REPLAY; - state.label = scenario->values["name"]; + state.label = translate_string_default((*scenario)["id"],(*scenario)["name"]); 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(scenario != NULL) { - state.label = (*scenario)["name"]; + state.label = translate_string_default((*scenario)["id"],(*scenario)["name"]); const int should_save = dialogs::get_save_name(disp, string_table["save_game_message"], diff --git a/src/game_config.cpp b/src/game_config.cpp index 270645af476..f3bccf8fa12 100644 --- a/src/game_config.cpp +++ b/src/game_config.cpp @@ -22,7 +22,7 @@ namespace game_config const int cure_amount = 8; const int curer_heals_per_turn = 18; const int recall_cost = 20; - const std::string version = "0.6RC2"; + const std::string version = "0.6RC3"; bool debug = false; #ifdef WESNOTH_PATH diff --git a/src/game_events.cpp b/src/game_events.cpp index 79d9dc548f9..67cf95272e4 100644 --- a/src/game_events.cpp +++ b/src/game_events.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -134,6 +135,7 @@ std::map* units = NULL; std::vector* teams = NULL; game_state* state_of_game = NULL; game_data* game_data_ptr = NULL; +std::set used_items; bool events_init() { return screen != NULL; } @@ -173,7 +175,7 @@ public: 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: std::string name_; @@ -218,31 +220,79 @@ std::vector multiple_locs(const config& cfg) std::multimap 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) cfg = cfg_; + std::vector::const_iterator i; + //sub commands that need to be handled in a guaranteed ordering - std::vector& commands = cfg->children["command"]; - for(std::vector::iterator cmd = commands.begin(); - cmd != commands.end(); ++cmd) { - handle_event(event_info,*cmd); + const config::child_list& commands = cfg->get_children("command"); + for(i = commands.begin(); i != commands.end(); ++i) { + handle_event(event_info,*i); + } + + //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(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(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(1,atoi((**i)["side"].c_str())); + const size_t index = side-1; + if(index > teams->size()) + continue; + + std::vector recruit = config::split((**i)["recruit"]); + if(recruit.size() == 1 && recruit.back() == "") + recruit.clear(); + + std::set& 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 - std::vector& sounds = cfg->children["sound"]; - for(std::vector::iterator sfx = sounds.begin(); - sfx != sounds.end(); ++sfx) { - sound::play_sound((*sfx)->values["name"]); + const config::child_list& sounds = cfg->get_children("sound"); + for(i = sounds.begin(); i != sounds.end(); ++i) { + sound::play_sound((**i)["name"]); } - std::vector& colour_adjust = cfg->children["colour_adjust"]; - for(std::vector::const_iterator col = colour_adjust.begin(); - col != colour_adjust.end(); ++col) { - const int r = atoi((**col)["red"].c_str()); - const int g = atoi((**col)["green"].c_str()); - const int b = atoi((**col)["blue"].c_str()); + const config::child_list& colour_adjust = cfg->get_children("colour_adjust"); + for(i = colour_adjust.begin(); i != colour_adjust.end(); ++i) { + const int r = atoi((**i)["red"].c_str()); + const int g = atoi((**i)["green"].c_str()); + const int b = atoi((**i)["blue"].c_str()); screen->adjust_colours(r,g,b); screen->invalidate_all(); 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 - std::vector& gold = cfg->children["gold"]; - for(std::vector::iterator gd = gold.begin(); gd!=gold.end();++gd) { - string_map& values = (*gd)->values; - const std::string& side = values["side"]; - const std::string& amount = values["amount"]; + const config::child_list& gold = cfg->get_children("gold"); + for(i = gold.begin(); i != gold.end(); ++i) { + const std::string& side = (**i)["side"]; + const std::string& amount = (**i)["amount"]; const int side_num = side.empty() ? 1 : atoi(side.c_str()); const int amount_num = atoi(amount.c_str()); 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 //the visual effect - std::vector& move_unit_fake = cfg->children["move_unit_fake"]; - for(std::vector::iterator muf = move_unit_fake.begin(); - muf != move_unit_fake.end(); ++muf) { - const std::string& type = (*muf)->values["type"]; - const game_data::unit_type_map::const_iterator itor = - game_data_ptr->unit_types.find(type); + const config::child_list& move_unit_fake = cfg->get_children("move_unit_fake"); + for(i = move_unit_fake.begin(); i != move_unit_fake.end(); ++i) { + const std::string& type = (**i)["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()) { unit dummy_unit(&itor->second,0); - const std::vector xvals = config::split((*muf)->values["x"]); - const std::vector yvals = config::split((*muf)->values["y"]); + const std::vector xvals = config::split((**i)["x"]); + const std::vector yvals = config::split((**i)["y"]); std::vector path; for(size_t i = 0; i != minimum(xvals.size(),yvals.size()); ++i) { 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 - std::vector& set_vars = cfg->children["set_variable"]; - for(std::vector::iterator var = set_vars.begin(); - var != set_vars.end(); ++var) { - string_map& vals = (*var)->values; - const std::string& name = vals["name"]; - const std::string& value = vals["value"]; + const config::child_list& set_vars = cfg->get_children("set_variable"); + for(i = set_vars.begin(); i != set_vars.end(); ++i) { + + const std::string& name = (**i)["name"]; + const std::string& value = (**i)["value"]; if(value.empty() == false) { state_of_game->variables[name] = value; } - const std::string& add = vals["add"]; + const std::string& add = (**i)["add"]; if(add.empty() == false) { double value = atof(state_of_game->variables[name].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; } - const std::string& multiply = vals["multiply"]; + const std::string& multiply = (**i)["multiply"]; if(multiply.empty() == false) { double value = atof(state_of_game->variables[name].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 - std::vector& conditionals = cfg->children["if"]; - for(std::vector::iterator cond = conditionals.begin(); - cond != conditionals.end(); ++cond) { + const config::child_list& conditionals = cfg->get_children("if"); + for(i = conditionals.begin(); i != conditionals.end(); ++i) { 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, //otherwise execute 'else' statements - std::vector& commands = (*cond)->children[type]; - for(std::vector::iterator cmd = commands.begin(); + const std::vector& commands = (*i)->get_children(type); + for(std::vector::const_iterator cmd = commands.begin(); cmd != commands.end(); ++cmd) { handle_event(event_info,*cmd); } } //if we are assigning a role to a unit from the available units list - std::vector& assign_role = cfg->children["role"]; - for(std::vector::iterator rl = assign_role.begin(); - rl != assign_role.end(); ++rl) { + const config::child_list& assign_role = cfg->get_children("role"); + for(i = assign_role.begin(); i != assign_role.end(); ++i) { //get a list of the types this unit can be - std::vector types = config::split((*rl)->values["type"]); + std::vector types = config::split((**i)["type"]); //iterate over all the types, and for each type, try to find //a unit that matches @@ -375,7 +419,7 @@ void event_handler::handle_event(const queued_event& event_info, config* cfg) std::map::iterator itor; for(itor = units->begin(); itor != units->end(); ++itor) { if(itor->second.matches_filter(cfg)) { - itor->second.assign_role((*rl)->values["role"]); + itor->second.assign_role((**i)["role"]); 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(); ui != state_of_game->available_units.end(); ++ui) { if(ui->matches_filter(cfg)) { - ui->assign_role((*rl)->values["role"]); + ui->assign_role((**i)["role"]); break; } } @@ -404,10 +448,9 @@ void event_handler::handle_event(const queued_event& event_info, config* cfg) break; } - std::vector& remove_overlays = cfg->children["removeitem"]; - for(std::vector::iterator rm = remove_overlays.begin(); - rm != remove_overlays.end(); ++rm) { - gamemap::location loc(**rm); + const config::child_list& remove_overlays = cfg->get_children("removeitem"); + for(i = remove_overlays.begin(); i != remove_overlays.end(); ++i) { + gamemap::location loc(**i); if(!loc.valid()) { loc = event_info.loc1; } @@ -416,25 +459,23 @@ void event_handler::handle_event(const queued_event& event_info, config* cfg) } //hiding units - std::vector& hide = cfg->children["hide_unit"]; - for(std::vector::iterator hd = hide.begin(); - hd != hide.end(); ++hd) { - const gamemap::location loc(**hd); + const config::child_list& hide = cfg->get_children("hide_unit"); + for(i = hide.begin(); i != hide.end(); ++i) { + const gamemap::location loc(**i); screen->hide_unit(loc); 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()); screen->draw_tile(loc.x,loc.y); } //adding new items - std::vector& add_overlays = cfg->children["item"]; - for(std::vector::iterator ni = add_overlays.begin(); - ni != add_overlays.end(); ++ni) { - gamemap::location loc(**ni); - const std::string& img = (*ni)->values["image"]; + const config::child_list& add_overlays = cfg->get_children("item"); + for(i = add_overlays.begin(); i != add_overlays.end(); ++i) { + gamemap::location loc(**i); + const std::string& img = (**i)["image"]; if(!img.empty()) { screen->add_overlay(loc,img); 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 - std::vector& terrain_changes = cfg->children["terrain"]; - for(std::vector::iterator tc = terrain_changes.begin(); - tc != terrain_changes.end(); ++tc) { - const std::vector locs = multiple_locs(**tc); + const config::child_list& terrain_changes = cfg->get_children("terrain"); + for(i = terrain_changes.begin(); i != terrain_changes.end(); ++i) { + const std::vector locs = multiple_locs(**i); for(std::vector::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) { game_map->set_terrain(*loc,terrain_type[0]); 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 - std::vector& new_units = cfg->children["unit"]; - for(std::vector::iterator ui = new_units.begin(); - ui != new_units.end(); ++ui) { - unit new_unit(*game_data_ptr,**ui); - gamemap::location loc(**ui); + const config::child_list& new_units = cfg->get_children("unit"); + for(i = new_units.begin(); i != new_units.end(); ++i) { + unit new_unit(*game_data_ptr,**i); + gamemap::location loc(**i); if(game_map->on_board(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 - std::vector& recalls = cfg->children["recall"]; - for(std::vector::iterator ir = recalls.begin(); - ir != recalls.end(); ++ir) { + const config::child_list& recalls = cfg->get_children("recall"); + for(i = recalls.begin(); i != recalls.end(); ++i) { std::vector& avail = state_of_game->available_units; - for(std::vector::iterator u = avail.begin(); - u != avail.end(); ++u) { - if(u->matches_filter(**ir)) { - recruit_unit(*game_map,1,*units,*u,gamemap::location(), - screen,false); + for(std::vector::iterator u = avail.begin(); u != avail.end(); ++u) { + if(u->matches_filter(**i)) { + recruit_unit(*game_map,1,*units,*u,gamemap::location(),screen,false); avail.erase(u); break; } } } - std::vector& objects = cfg->children["object"]; - for(std::vector::iterator obj = objects.begin(); - obj != objects.end(); ++obj) { - string_map& values = (*obj)->values; - - //if this item has already been used - if(values["used"].empty() == false) - continue; + const config::child_list& objects = cfg->get_children("object"); + for(i = objects.begin(); i != objects.end(); ++i) { + const config& values = **i; 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"]; 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) caption = caption_lang; - const std::map::iterator u = - units->find(event_info.loc1); + const std::map::iterator u = units->find(event_info.loc1); if(u == units->end()) continue; std::string text; - std::vector& filters = (*obj)->children["filter"]; + const config::child_list& filters = (*i)->get_children("filter"); if(filters.empty() || u->second.matches_filter(*filters[0])) { const std::string& lang = string_table[id]; @@ -524,13 +558,13 @@ void event_handler::handle_event(const queued_event& event_info, config* cfg) else text = values["description"]; - u->second.add_modification("object",**obj); + u->second.add_modification("object",**i); screen->remove_overlay(event_info.loc1); screen->select_hex(event_info.loc1); screen->invalidate_unit(); //mark that this item won't be used again - values["used"] = "true"; + used_items.insert(id); } else { const std::string& lang = string_table[id + "_cannot_use"]; if(!lang.empty()) @@ -551,10 +585,9 @@ void event_handler::handle_event(const queued_event& event_info, config* cfg) screen->draw(); } - std::vector& messages = cfg->children["message"]; - for(std::vector::iterator msg = messages.begin(); - msg != messages.end(); ++msg) { - string_map& values = (*msg)->values; + const config::child_list& messages = cfg->get_children("message"); + for(i = messages.begin(); i != messages.end(); ++i) { + const config& values = **i; std::map::iterator speaker = units->end(); 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") { for(speaker = units->begin(); speaker != units->end(); ++speaker){ - if(speaker->second.matches_filter(**msg)) + if(speaker->second.matches_filter(**i)) 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"); - if(sfx != values.end()) { - sound::play_sound(sfx->second); + const std::string& sfx = values["sound"]; + if(sfx != "") { + sound::play_sound(sfx); } const std::string& id = values["id"]; - std::string image = (*msg)->values["image"]; + std::string image = values["image"]; std::string caption; const std::string& lang_caption = string_table[id + "_caption"]; if(!lang_caption.empty()) caption = lang_caption; else - caption = (*msg)->values["caption"]; + caption = values["caption"]; if(speaker != units->end()) { screen->highlight_hex(speaker->first); @@ -610,12 +643,12 @@ void event_handler::handle_event(const queued_event& event_info, config* cfg) std::vector options; std::vector*> option_events; - std::vector& menu_items = (*msg)->children["option"]; - for(std::vector::iterator mi = menu_items.begin(); + std::cerr << "building menu items...\n"; + + const std::vector& menu_items = (*i)->get_children("option"); + for(std::vector::const_iterator mi = menu_items.begin(); mi != menu_items.end(); ++mi) { - const std::string& lang_msg = string_table[(*mi)->values["id"]]; - const std::string& msg = lang_msg.empty() ? - (*mi)->values["message"] : lang_msg; + const std::string& msg = translate_string_default((**mi)["id"],(**mi)["message"]); options.push_back(msg); 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(); } - const std::string& val = - cfg->children["choose"].front()->values["value"]; + if(size_t(option_chosen) >= options.size()) { + option_chosen = 0; + } + + const std::string& val = cfg->children["choose"].front()->values["value"]; option_chosen = atol(val.c_str()); } 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) { assert(size_t(option_chosen) < menu_items.size()); - std::vector& events = *option_events[option_chosen]; - for(std::vector::iterator ev = events.begin(); + const std::vector& events = *option_events[option_chosen]; + for(std::vector::const_iterator ev = events.begin(); ev != events.end(); ++ev) { handle_event(event_info,*ev); } } } - std::vector& dead_units = cfg->children["kill"]; - for(std::vector::iterator du = dead_units.begin(); - du != dead_units.end(); ++du) { + const config::child_list& dead_units = cfg->get_children("kill"); + for(i = dead_units.begin(); i != dead_units.end(); ++i) { - for(std::map::iterator i = units->begin(); - i != units->end(); ++i) { - while(i->second.matches_filter(**du) && i != units->end()) { - units->erase(i); - i = units->begin(); + for(std::map::iterator un = units->begin(); + un != units->end(); ++un) { + while(un != units->end() && un->second.matches_filter(**i)) { + units->erase(un); + un = units->begin(); } } std::vector& avail_units = state_of_game->available_units; for(std::vector::iterator j = avail_units.begin(); 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); } } } //adding of new events - std::vector& new_events = cfg->children["event"]; - for(std::vector::iterator ne = new_events.begin(); - ne != new_events.end(); ++ne) { - event_handler new_handler(*ne); + const config::child_list& new_events = cfg->get_children("event"); + for(i = new_events.begin(); i != new_events.end(); ++i) { + event_handler new_handler(*i); events_map.insert(std::pair( new_handler.name(),new_handler)); } @@ -832,6 +866,8 @@ manager::manager(config& cfg, display& gui_, gamemap& map_, units = &units_; state_of_game = &state_of_game_; game_data_ptr = &game_data_; + + used_items.clear(); } manager::~manager() { diff --git a/src/gamestatus.cpp b/src/gamestatus.cpp index f54814a5a05..c18fa36a27f 100644 --- a/src/gamestatus.cpp +++ b/src/gamestatus.cpp @@ -18,6 +18,7 @@ #include #include +#include #include 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.can_recruit.clear(); + + const std::string& can_recruit_str = (*cfg)["can_recruit"]; + if(can_recruit_str != "") { + const std::vector 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; } @@ -151,6 +160,16 @@ void write_game(const game_state& game, config& cfg) } 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(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. diff --git a/src/gamestatus.hpp b/src/gamestatus.hpp index 9f76b0453f3..50dbae992fb 100644 --- a/src/gamestatus.hpp +++ b/src/gamestatus.hpp @@ -88,10 +88,12 @@ struct game_state std::string campaign_type; //type of the game - campaign, multiplayer etc std::string scenario; //the scenario being played int gold; //amount of gold the player has saved - std::vector available_units; //units the player has to recall + std::vector available_units; //units the player may recall std::map variables; //variables that have been set std::string difficulty; //the difficulty level the game is being played on. + std::set 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 //take the game up to the position it was saved at. config replay_data; diff --git a/src/language.cpp b/src/language.cpp index 1c4b16c4ee4..ee2532d6cc0 100644 --- a/src/language.cpp +++ b/src/language.cpp @@ -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 string_map::const_iterator i = string_table.find(str); - if(i != string_table.end()) + if(i != string_table.end() && i->second != "") return i->second; else return default_val; diff --git a/src/map.cpp b/src/map.cpp index 9b1ebca44ff..c9eef15adec 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -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& ystr = cfg.values["y"]; + const std::string& xstr = cfg["x"]; + const std::string& ystr = cfg["y"]; //the co-ordinates in config files will be 1-based, while we //want them as 0-based diff --git a/src/map.hpp b/src/map.hpp index 7a7ee87189b..885089ab773 100644 --- a/src/map.hpp +++ b/src/map.hpp @@ -57,7 +57,7 @@ public: location() : x(-1), y(-1) {} location(int x, int y) : x(x), y(y) {} - location(config& cfg); + location(const config& cfg); bool valid() const { return x >= 0 && y >= 0; } diff --git a/src/playlevel.cpp b/src/playlevel.cpp index 13ca456d924..fe0265c4dac 100644 --- a/src/playlevel.cpp +++ b/src/playlevel.cpp @@ -25,6 +25,7 @@ #include "tooltips.hpp" #include +#include LEVEL_RESULT play_level(game_data& gameinfo, config& terrain_config, config* level, CVideo& video, @@ -68,26 +69,35 @@ LEVEL_RESULT play_level(game_data& gameinfo, config& terrain_config, if(gold.empty()) gold = "100"; - const int minimum_gold = 100; - 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") ngold = state_of_game.gold; - const gamemap::location& start_pos = - map.starting_position(new_unit.side()); + const gamemap::location& start_pos = map.starting_position(new_unit.side()); - if(!start_pos.valid()) { - std::stringstream err; - err << "No starting position for side " << new_unit.side(); - throw gamestatus::load_game_failed(err.str()); + if(!start_pos.valid() && new_unit.side() == 1) { + throw gamestatus::load_game_failed("No starting position for side 1"); + } + + if(start_pos.valid()) { + units.insert(std::pair( + map.starting_position(new_unit.side()), new_unit)); } - units.insert(std::pair( - map.starting_position(new_unit.side()), new_unit)); 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()) { first_human_team = teams.size()-1; } @@ -373,10 +383,6 @@ LEVEL_RESULT play_level(game_data& gameinfo, config& terrain_config, } catch(end_level_exception&) { } - if((*level)["disallow_recall"] == "yes") { - return VICTORY; - } - //add all the units that survived the scenario for(std::map::iterator 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 finishing_bonus_per_turn = map.towers().size()*game_config::tower_income; diff --git a/src/playturn.cpp b/src/playturn.cpp index edaf0bfc3dd..61022f45075 100644 --- a/src/playturn.cpp +++ b/src/playturn.cpp @@ -613,6 +613,11 @@ void turn_info::show_menu() 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()) { menu.push_back(string_table["describe_unit"]); @@ -631,7 +636,24 @@ void turn_info::show_menu() menu.pop_back(); } - if(result == string_table["describe_unit"]) { + if(result == create_unit_debug) { + std::vector options; + std::vector 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(last_hex_,unit_choices[choice])); + gui_.invalidate(last_hex_); + gui_.invalidate_unit(); + } + } else if(result == string_table["describe_unit"]) { unit_description(); } else if(result == string_table["rename_unit"]) { rename_unit(); @@ -1003,7 +1025,7 @@ void turn_info::rename_unit() void turn_info::save_game() { std::stringstream stream; - stream << translate_string(state_of_game_.scenario) << " " << string_table["turn"] + stream << state_of_game_.label << " " << string_table["turn"] << " " << status_.turn(); std::string label = stream.str(); @@ -1189,8 +1211,12 @@ void turn_info::recall() << string_table["level"] << ": " << unit->type().level() << "," << string_table["xp"] << ": " - << unit->experience() << "/" - << unit->max_experience(); + << unit->experience() << "/"; + + if(unit->type().advances_to().empty()) + option << "-"; + else + option << unit->max_experience(); options.push_back(option.str()); } diff --git a/src/replay.cpp b/src/replay.cpp index a67260fbae7..d46a01126c0 100644 --- a/src/replay.cpp +++ b/src/replay.cpp @@ -58,6 +58,16 @@ int 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) {} @@ -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() { pos_ = 0; @@ -537,7 +560,9 @@ bool do_replay(display& disp, const gamemap& map, const game_data& gameinfo, std::map::const_iterator tgt = units.find(dst); 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(); } diff --git a/src/replay.hpp b/src/replay.hpp index f95b7111551..7023fc425dc 100644 --- a/src/replay.hpp +++ b/src/replay.hpp @@ -19,6 +19,9 @@ int get_random(); +const config* get_random_results(); +void set_random_results(const config& cfg); + class replay { public: @@ -50,6 +53,8 @@ public: void undo(); int get_random(); + const config* get_random_results() const; + void set_random_results(const config& cfg); void start_replay(); config* get_next_action(); diff --git a/src/show_dialog.cpp b/src/show_dialog.cpp index 71b7aea8677..31050c344af 100644 --- a/src/show_dialog.cpp +++ b/src/show_dialog.cpp @@ -379,7 +379,7 @@ int show_dialog(display& disp, SDL_Surface* image, text_widget_height + check_button_height; if(total_width > scr->w - 100 || total_height > scr->h - 100) - return false; + return 0; int xloc = scr->w/2 - total_width/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 if(xloc + total_width+border_size >= disp.mapx()-1) { + std::cerr << "in if...\n"; xloc = disp.mapx()-(total_width+border_size+2); - if(xloc < 0) - return -1; + if(xloc < 0) { + std::cerr << "dialog is too large to fit on-screen!\n"; + return 0; + } } const int button_hpadding = total_width - button_widths; diff --git a/src/team.cpp b/src/team.cpp index 62f7358e75c..d709948a879 100644 --- a/src/team.cpp +++ b/src/team.cpp @@ -157,6 +157,11 @@ const std::set& team::recruits() const return info_.can_recruit; } +std::set& team::recruits() +{ + return info_.can_recruit; +} + const std::vector& team::recruitment_pattern() const { return info_.recruitment_pattern; diff --git a/src/team.hpp b/src/team.hpp index c573bffccd7..fda0e24ea1b 100644 --- a/src/team.hpp +++ b/src/team.hpp @@ -69,6 +69,7 @@ public: void spend_gold(int amount); const std::set& recruits() const; + std::set& recruits(); const std::vector& recruitment_pattern() const; const std::string& name() const;