added shroud. Tweaked some units, added new scenario

This commit is contained in:
Dave White 2003-10-01 09:23:38 +00:00
parent 2be9acb023
commit afdb6002e6
48 changed files with 925 additions and 166 deletions

View File

@ -7,6 +7,13 @@
[units] [units]
{units} {units}
[trait]
name=loyal
[effect]
apply_to=loyal
[/effect]
[/trait]
[trait] [trait]
name=strong name=strong
[effect] [effect]
@ -38,7 +45,7 @@
name=intelligent name=intelligent
[effect] [effect]
apply_to=max_experience apply_to=max_experience
increase=-7 increase=-6
[/effect] [/effect]
[/trait] [/trait]
@ -64,6 +71,8 @@
mountains=3 mountains=3
village=1 village=1
castle=1 castle=1
cave=2
cavewall=100
[/movement costs] [/movement costs]
[defense] [defense]
@ -76,6 +85,8 @@
mountains=0.4 mountains=0.4
village=0.4 village=0.4
castle=0.4 castle=0.4
cave=0.6
cavewall=0.1
[/defense] [/defense]
[resistance] [resistance]
@ -100,6 +111,8 @@
mountains=2 mountains=2
village=1 village=1
castle=1 castle=1
cave=1
cavewall=100
[/movement costs] [/movement costs]
[defense] [defense]
@ -112,6 +125,7 @@
mountains=0.4 mountains=0.4
village=0.6 village=0.6
castle=0.6 castle=0.6
cave=0.6
[/defense] [/defense]
[resistance] [resistance]
@ -136,6 +150,8 @@
mountains=3 mountains=3
village=1 village=1
castle=1 castle=1
cave=1
cavewall=100
[/movement costs] [/movement costs]
[defense] [defense]
@ -148,6 +164,7 @@
mountains=0.3 mountains=0.3
village=0.3 village=0.3
castle=0.3 castle=0.3
cave=0.5
[/defense] [/defense]
[resistance] [resistance]
@ -173,6 +190,8 @@
mountains=100 mountains=100
village=1 village=1
castle=1 castle=1
cave=4
cavewall=100
[/movement costs] [/movement costs]
[defense] [defense]
@ -185,6 +204,7 @@
mountains=0.8 mountains=0.8
village=0.6 village=0.6
castle=0.6 castle=0.6
cave=0.8
[/defense] [/defense]
[resistance] [resistance]
@ -209,6 +229,8 @@
mountains=4 mountains=4
village=1 village=1
castle=1 castle=1
cave=3
cavewall=100
[/movement costs] [/movement costs]
[defense] [defense]
@ -221,6 +243,7 @@
mountains=0.4 mountains=0.4
village=0.4 village=0.4
castle=0.4 castle=0.4
cave=0.7
[/defense] [/defense]
[resistance] [resistance]
@ -245,6 +268,8 @@
mountains=1 mountains=1
village=1 village=1
castle=1 castle=1
cave=2
cavewall=100
[/movement costs] [/movement costs]
[defense] [defense]
@ -257,6 +282,7 @@
mountains=0.7 mountains=0.7
village=0.7 village=0.7
castle=0.7 castle=0.7
cave=0.7
[/defense] [/defense]
[resistance] [resistance]
@ -281,6 +307,8 @@
mountains=100 mountains=100
village=1 village=1
castle=1 castle=1
cave=3
cavewall=100
[/movement costs] [/movement costs]
[defense] [defense]
@ -293,6 +321,7 @@
mountains=0.8 mountains=0.8
village=0.6 village=0.6
castle=0.6 castle=0.6
cave=0.8
[/defense] [/defense]
[resistance] [resistance]
@ -317,6 +346,8 @@
mountains=1 mountains=1
village=1 village=1
castle=1 castle=1
cave=1
cavewall=100
[/movement costs] [/movement costs]
[defense] [defense]
@ -329,6 +360,7 @@
mountains=0.3 mountains=0.3
village=0.6 village=0.6
castle=0.6 castle=0.6
cave=0.5
[/defense] [/defense]
[resistance] [resistance]
@ -341,42 +373,6 @@
[/resistance] [/resistance]
[/movetype] [/movetype]
[movetype]
name=largemountain
[movement costs]
deep water=100
shallow water=100
grassland=1
sand=2
forest=3
hills=1
mountains=1
village=1
castle=1
[/movement costs]
[defense]
deep water=0.8
shallow water=0.7
grassland=0.7
sand=0.7
forest=0.7
hills=0.6
mountains=0.4
village=0.6
castle=0.6
[/defense]
[resistance]
blade=0.8
pierce=1.0
impact=1.0
fire=1.0
cold=1.0
holy=0.8
[/resistance]
[/movetype]
[movetype] [movetype]
name=undeadfoot name=undeadfoot
[movement costs] [movement costs]
@ -389,6 +385,8 @@
mountains=100 mountains=100
village=1 village=1
castle=1 castle=1
cave=2
cavewall=100
[/movement costs] [/movement costs]
[defense] [defense]
@ -401,6 +399,7 @@
mountains=0.4 mountains=0.4
village=0.4 village=0.4
castle=0.4 castle=0.4
cave=0.6
[/defense] [/defense]
[resistance] [resistance]
@ -425,6 +424,8 @@
mountains=1 mountains=1
village=1 village=1
castle=1 castle=1
cave=1
cavewall=100
[/movement costs] [/movement costs]
[defense] [defense]
@ -437,6 +438,7 @@
mountains=0.5 mountains=0.5
village=0.5 village=0.5
castle=0.5 castle=0.5
cave=0.6
[/defense] [/defense]
[resistance] [resistance]

31
data/maps/map12 Normal file
View File

@ -0,0 +1,31 @@
uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
uuuuuuuuuuuuuuuWWWWuWuuuuuuuuuuuuuuuuWuuu
uuuuuuuuuuuuuWWuuWWWWWuuuuuuuuuuuuuWWWuuu
uuuuuuuuuuuuuWuCCuuuuuWuuuuuuuuuuuuWuuWWu
uuuuuuuuuuuuWuCCCCCCCuWuuuuuuuuuuuWuuuuWu
uuuuuuuuuuuuWuuCCCCCCuWWuuuuuuuuWWuWuuuuW
uuuuuuuuuuuuWuuCCCCCuCWWuuuuuuuWuWWuuuuuW
uuuuuuuuuuuuWWuCCCCCuCuWWWuuuuuWuuuuuuuuW
CCuuuuuuuuuuWuCCCC3CCuuuWWWWWuuWuuuuuuuuW
u2CuuuuuuuuuuWuCCCCCCuuuuuuWWWWWuuuuWuuuW
uCuuuuuuuuuuuWuCCCCCuuuuuuuuuWWWWuuWuWuuW
uuuuuuuuuuuuuWuCCCCCcCuuuuuuuuWuWWWWuWuuW
uuuuuuuuuuuuuWuCCCCCcWWWuuuuuuuuuWWWWWWuW
uuuuuuuuuuuuuuWCCCCCccWWWuuuuuuuuuWuWWWWW
uuuuuuuuuuuuuuWuuuucWWuuWWWuuuuuuuuuuuuWW
uuuuuuuuuuuuuuuWWuuWWuuuuuWWuuuuuuuuuuuuW
uuuuuuuuuuuuuuuuWWWuuuuuuuWWuuuuuuuuuuuuW
uuuuuuuuuuuuuuuuuuuuuuuuuuuuWWuuuuuuuuuuW
uuuuuuuuuuuuuuuuuuuuuuuuuuuuWWWWWWWuuuuuW
uuuuuuuuuuuuuuuuuuuuuuuuuuuuWWWWWWWWuuuuW
uuuuuuuuuuuuuuuuuuuuuuuuuuuuuWWuuuuWuuuuW
uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuWuuuW
uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuWWuuuW
uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuWuuuu
uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuWuuuu
uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuWuuu
uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuWuuu
uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuWu1

View File

@ -15,7 +15,7 @@
[/side] [/side]
[side] [side]
type=Orcish Grunt type=Orcish Crossbow
description=Urug-Telfar description=Urug-Telfar
side=2 side=2
canrecruit=1 canrecruit=1

View File

@ -54,6 +54,7 @@ Defeat:
side=2 side=2
canrecruit=1 canrecruit=1
recruit=Vampire Bat,Naga recruit=Vampire Bat,Naga
recruitment_pattern=scout,fighter
#ifdef EASY #ifdef EASY
gold=100 gold=100
#endif #endif

View File

@ -74,8 +74,8 @@ Defeat:
description=Knafa-Telfar description=Knafa-Telfar
side=2 side=2
canrecruit=1 canrecruit=1
recruit=Orcish Warrior,Wolf Rider,Orcish Crossbow,Orcish Assasin,Troll recruit=Orcish Warrior,Wolf Rider,Orcish Crossbow,Orcish Assasin,Troll Warrior
gold=250 gold=450
enemy=1 enemy=1
[/side] [/side]
@ -84,8 +84,8 @@ Defeat:
description=Urug-Tan description=Urug-Tan
side=3 side=3
canrecruit=1 canrecruit=1
recruit=Orcish Grunt,Goblin Knight,Orcish Crossbow,Orcish Assasin,Troll recruit=Orcish Grunt,Goblin Knight,Orcish Crossbow,Orcish Assasin,Troll Warrior
gold=300 gold=500
enemy=1 enemy=1
[/side] [/side]
@ -96,7 +96,7 @@ Defeat:
side=4 side=4
canrecruit=1 canrecruit=1
recruit=Orcish Warrior,Wolf Rider,Orcish Crossbow,Troll Warrior,Orcish Slayer recruit=Orcish Warrior,Wolf Rider,Orcish Crossbow,Troll Warrior,Orcish Slayer
gold=300 gold=500
enemy=1 enemy=1
[/side] [/side]

View File

@ -0,0 +1,351 @@
[scenario]
name="Scenario 11B: Plunging into the Darkness"
map=map12
turns=16
id=scenario12
[bigmap]
image=misc/map.png
[dot]
type=cross
x=187
y=187
[/dot]
[/bigmap]
objectives="
Victory:
@Find the Dwarves
Defeat
#Death of Konrad
#Death of Delfador
#Death of Kalenz
#Death of Li'sar"
[side]
type=Commander
description=Konrad
side=1
canrecruit=1
controller=human
recruit=Elvish Fighter,Elvish Archer,Horseman,Mage,Elvish Shaman,Merman,Thief,Gryphon Rider
enemy=2
shroud=yes
[/side]
[side]
type=Orcish Warlord
side=2
canrecruit=1
recruit=Orcish Warrior
gold=0
enemy=1
aggression=1.0
[unit]
type=Blood Bat
x=17
y=36
side=2
ai_special=guardian
[/unit]
[unit]
type=Blood Bat
x=21
y=31
side=2
ai_special=guardian
[/unit]
[unit]
type=Blood Bat
x=15
y=32
side=2
ai_special=guardian
[/unit]
[unit]
type=Blood Bat
x=15
y=25
side=2
ai_special=guardian
[/unit]
[unit]
type=Giant Spider
x=16
y=40
side=2
[/unit]
[/side]
[side]
description=Geldar
type=Dwarvish Lord
side=3
canrecruit=1
recruit=Dwarvish Fighter
gold=0
enemy=4 #dummy non-existent side
[unit]
type=Dwarvish Fighter
x=15
y=22
side=3
ai_special=guardian
[/unit]
[unit]
type=Dwarvish Fighter
x=10
y=22
side=3
ai_special=guardian
[/unit]
[unit]
type=Dwarvish Fighter
x=13
y=20
side=3
ai_special=guardian
[/unit]
[unit]
type=Dwarvish Fighter
x=11
y=20
side=3
ai_special=guardian
[/unit]
[unit]
type=Dwarvish Fighter
x=13
y=19
side=3
ai_special=guardian
[/unit]
[unit]
type=Dwarvish Fighter
x=11
y=19
side=3
ai_special=guardian
[/unit]
[unit]
type=Dwarvish Fighter
x=8
y=20
side=3
ai_special=guardian
[/unit]
[unit]
type=Dwarvish Fighter
x=17
y=19
side=3
ai_special=guardian
[/unit]
[unit]
type=Dwarvish Fighter
x=15
y=16
side=3
ai_special=guardian
[/unit]
[unit]
type=Dwarvish Fighter
x=9
y=16
side=3
ai_special=guardian
[/unit]
[/side]
[event]
name=start
[recall]
description=Delfador
[/recall]
[recall]
description=Kalenz
[/recall]
[recall]
description=Li'sar
[/recall]
[message]
id=msg12_1
description=Konrad
message="It's so dark in here! I can hardly see!"
[/message]
[message]
id=msg12_2
description=Delfador
message="It is dark indeed. We shall have to light torches, and tread slowly and warily. Hopefully there are still Dwarves down here who can aid us!"
[/message]
[message]
id=msg12_3
description=Kalenz
message="Indeed. Us Elves are not well-skilled in these dark pits."
[/message]
[message]
id=msg12_4
description=Li'sar
message="This isn't so bad. When I grew up in the castle, I often used to explore the secret passages."
[/message]
[/event]
[event]
name=moveto
[filter]
side=1
y=10-21
x=1-100
[/filter]
[message]
id=msg12_5
description=Geldar
message="Who are these that approach? Surface-dwellers! On guard men!"
[/message]
[message]
id=msg12_6
description=Delfador
message="We come in peace, friends. We come in peace!"
[/message]
[message]
id=msg12_7
description=Geldar
message="Oh do you? I see you are even accompanied by Elves. Can us Dwarves not live in peace without the treacherous Elves coming to bother us?"
[/message]
[message]
id=msg12_8
description=Kalenz
message="Why such harsh words, Dwarf? Elves have never done you any harm."
[/message]
[message]
id=msg12_9
description=Geldar
message="Never done us any harm? Why I was there myself, when the Elves did not come to honor our alliance. Many Dwarves were slaughtered, and you cowardly Elves did nothing to help!"
[/message]
[message]
id=msg12_10
description=Kalenz
message="You go too far! I am Kalenz, a mighty Elvish lord! How dare such as you, snivelling around in his tunnel, dare to call me a coward?"
[/message]
[message]
id=msg12_11
description=Delfador
message="Peace friends! Peace! The evil Orcs roam the lands above us, must we also fight among ourselves?"
[/message]
[message]
id=msg12_12
description=Geldar
message="Very well! Who are you? Explain your presence here then, human. Why have you risked life and limb to come to Knalga, the home of the Dwarves?"
[/message]
[message]
id=msg12_13
description=Konrad
message="Well, we....we..."
[/message]
[message]
id=msg12_14
description=Delfador
message="We have come so that an heir may claim his inheritance. That a king may claim his throne. We seek the Sceptre of Fire."
[/message]
[message]
id=msg12_15
description=Geldar
message="The Sceptre of Fire? Are you out of your mind? Surely you speak but only in jest!"
[/message]
[message]
id=msg12_16
description=Delfador
message="We jest not, friend. We seek the Sceptre of Fire. We seek the help of the Dwarves in finding it. Choose to help us not, if you so wish. We will find it, whether you help us or not."
[/message]
[message]
id=msg12_17
description=Geldar
message="Your speech is like that of a fool. No-one even knows if the Sceptre of Fire exists. Who is this heir, this king that you speak of, anyhow?"
[/message]
[message]
id=msg12_18
description=Konrad
message="I am, Sir."
[/message]
[message]
id=msg12_19
description=Geldar
message="You, haha, this boy that stands before me is the king of Wesnoth? Haha! I haven't had such a laugh in a long time. And whom are you, old man?"
[/message]
[message]
id=msg12_20
description=Delfador
message="I am Delfador. Delfador the Great, Arch Mage to King Garard, and Protector of his heir."
[/message]
[message]
id=msg12_21
description=Geldar
message="You....you are Delfador? I have seen Delfador when I was but a young Dwarf, and I will tell you old man, you are not Delfador. Men! Take these liars out of my sight. Delfador perished many years ago."
[/message]
[message]
sound=lightning.wav
id=msg12_22
description=Delfador
message="I am Delfador the Great! Any who dare oppose me shall perish!"
[/message]
[message]
id=msg12_23
description=Geldar
message="You...you really are Delfador! But we had news that you were dead, years ago!"
[/message]
[message]
id=msg12_24
description=Delfador
message="They thought I was dead. They hoped I was dead. Yet still, still I live."
[/message]
[message]
id=msg12_25
description=Geldar
message="And you really think you can find, the Sceptre of Fire?"
[/message]
[message]
id=msg12_26
description=Delfador
message="Yes we do. If you help us, friend, all the treasures of Knalga that we find are yours. We want only the Sceptre. It will be dangerous. Make no mistake about that: Dwarves will be killed, perhaps many Dwarves. But surely it is better than hiding from the Orcs like worms."
[/message]
[message]
id=msg12_27
description=Geldar
message="You are right, friend. I will put my best men at your disposal. We know not where the Sceptre is though. Legend says it is hidden in the northern tunnels."
[/message]
[message]
id=msg12_28
description=Delfador
message="Then to the northern tunnels we shall go!"
[/message]
[endlevel]
result=victory
[/endlevel]
[/event]
#a secret passage that only Li'sar can find
[event]
name=moveto
[filter]
x=17
y=36
type=Princess
[/filter]
[message]
speaker=unit
message="Hmm...there seems to be a secret passage behind these rocks!"
[/message]
[terrain]
x=16
y=36
letter=u
[/terrain]
[/event]
{deaths.cfg}
[/scenario]

View File

@ -96,3 +96,20 @@ red=100
green=100 green=100
blue=100 blue=100
[/terrain] [/terrain]
[terrain]
image=cavewall
name=cavewall
char=W
red=50
green=50
blue=20
[/terrain]
[terrain]
image=cave
name=cave
char=u
red=120
green=120
[/terrain]

View File

@ -17,8 +17,8 @@ language="English"
[/hotkey] [/hotkey]
[hotkey] [hotkey]
command=recall command=recall
key=c key=r
ctrl=yes alt=yes
[/hotkey] [/hotkey]
[hotkey] [hotkey]
command=cycle command=cycle
@ -73,6 +73,11 @@ language="English"
key=s key=s
ctrl=yes ctrl=yes
[/hotkey] [/hotkey]
[hotkey]
command=endturn
key=e
alt=yes
[/hotkey]
game_title="The Battle for Wesnoth" game_title="The Battle for Wesnoth"
version="Version" version="Version"
@ -143,12 +148,13 @@ early_finish_bonus="Early finish bonus"
per_turn="per turn" per_turn="per turn"
turns_finished_early="Turns finished early" turns_finished_early="Turns finished early"
retained_gold="Retained Gold" retained_gold="Retained Gold"
fifty_percent="50% of gold is retained for the next scenario" fifty_percent="80% of gold is retained for the next scenario"
bonus="Bonus" bonus="Bonus"
gold="Gold" gold="Gold"
turn="Turn" turn="Turn"
villages="Villages" villages="Villages"
units="Units" units="Units"
upkeep="Upkeep"
income="Income" income="Income"
name="Name" name="Name"
@ -221,6 +227,7 @@ movement="Movement"
defense="Defense" defense="Defense"
attack_resistance="Resistance" attack_resistance="Resistance"
unit_resistance_table="Unit resistance table"
close_window="Close Window" close_window="Close Window"
see_also="See Also..." see_also="See Also..."
@ -242,5 +249,7 @@ forest="Forest"
bridge="Bridge" bridge="Bridge"
castle="Castle" castle="Castle"
keep="Keep" keep="Keep"
cave="Cave"
cavewall="Cave Wall"
[/language] [/language]

View File

@ -0,0 +1,31 @@
[unit]
name=Giant Spider
image=cavespider.png
hitpoints=54
movement_type=mountainfoot
movement=6
experience=500
level=3
alignment=chaotic
advanceto=null
cost=48
usage=fighter
unit_description="Giant spiders are said to roam the depths of Knalga, devouring many victims. They can bite at close range, poisoning their enemies, and attack with a web at long range, slowing their foes down."
[attack]
name=bite
type=blade
range=short
damage=18
number=2
special=poison
[/attack]
[attack]
name=web
type=impact
range=long
damage=8
number=3
special=slows
[/attack]
[/unit]

View File

@ -0,0 +1,22 @@
[unit]
name=Dwarvish Fighter
image=dwarf-fighter.png
hitpoints=38
movement_type=mountainfoot
movement=4
experience=42
level=1
alignment=neutral
advanceto=Dwarvish Lord
cost=15
usage=fighter
unit_description="The Dwarvish Fighters are excellent underground and in mountainous terrain. Skilled at close range combat, the sheer power of their battle axe makes them a feared opponent. Their power and endurance makes up for their slow speed."
[attack]
name=battle axe
type=blade
range=short
damage=8
number=3
[/attack]
[/unit]

View File

@ -8,7 +8,7 @@ experience=42
level=1 level=1
alignment=lawful alignment=lawful
advanceto=Elvish Ranger,Elvish Marksman advanceto=Elvish Ranger,Elvish Marksman
cost=22 cost=18
usage=scout usage=scout
unit_description="Being trained from youth in archery, the Elvish Archer is skilled in long range combat. Being able to fire many arrows quickly and accurately, the Elvish Archer makes up a large portion of the Elvish military." unit_description="Being trained from youth in archery, the Elvish Archer is skilled in long range combat. Being able to fire many arrows quickly and accurately, the Elvish Archer makes up a large portion of the Elvish military."
[attack] [attack]

View File

@ -4,7 +4,7 @@ image=elvish-avenger.png
hitpoints=60 hitpoints=60
movement_type=woodland movement_type=woodland
movement=6 movement=6
experience=80 experience=500
level=3 level=3
alignment=lawful alignment=lawful
advanceto=null advanceto=null
@ -23,7 +23,7 @@ unit_description="Extremely skillful and extremely quick, the Elvish Avenger is
name=bow name=bow
type=pierce type=pierce
range=long range=long
damage=12 damage=11
number=4 number=4
[sound] [sound]
time=-100 time=-100

View File

@ -1,6 +1,7 @@
[unit] [unit]
name=Elvish Fighter name=Elvish Fighter
image=elvish-fighter.png image=elvish-fighter.png
image_long=elvish-fighter-bow.png
image_defensive=elvish-fighter-defend.png image_defensive=elvish-fighter-defend.png
image_defensive_long=elvish-fighter-bow-defend.png image_defensive_long=elvish-fighter-bow-defend.png
hitpoints=32 hitpoints=32

View File

@ -23,7 +23,7 @@ unit_description="The Elvish Ranger is quick and powerful. Skilled in both short
name=bow name=bow
type=pierce type=pierce
range=long range=long
damage=8 damage=7
number=4 number=4
[sound] [sound]
time=-100 time=-100

View File

@ -9,7 +9,7 @@ experience=32
level=1 level=1
alignment=neutral alignment=neutral
advanceto=Elvish Druid advanceto=Elvish Druid
cost=27 cost=21
usage=healer usage=healer
unit_description="The Elvish Shaman focuses on less violent ways to hinder the enemy. Her entangling attack slows enemies down and reduces the number of times they may attack. She also possesses basic healing abilities." unit_description="The Elvish Shaman focuses on less violent ways to hinder the enemy. Her entangling attack slows enemies down and reduces the number of times they may attack. She also possesses basic healing abilities."

View File

@ -8,7 +8,7 @@ experience=38
level=1 level=1
alignment=neutral alignment=neutral
advanceto=Knight,Elvish Outrider advanceto=Knight,Elvish Outrider
cost=28 cost=23
usage=fighter usage=fighter
unit_description="Trained from childhood to ride, Horsemen are both fast and powerful at attacking. Charging at their enemies, their attacks do double damage, but also cause the horsemen to receive double damage when struck." unit_description="Trained from childhood to ride, Horsemen are both fast and powerful at attacking. Charging at their enemies, their attacks do double damage, but also cause the horsemen to receive double damage when struck."
[attack] [attack]

View File

@ -8,7 +8,7 @@ experience=45
level=1 level=1
alignment=neutral alignment=neutral
advanceto=White Mage,Red Mage advanceto=White Mage,Red Mage
cost=42 cost=34
usage=mixed fighter usage=mixed fighter
unit_description="The mage is weak and yet potent. Moving slowly, and weak defensively, the mage attacks with magical missiles, that always have a high chance of hitting their target. unit_description="The mage is weak and yet potent. Moving slowly, and weak defensively, the mage attacks with magical missiles, that always have a high chance of hitting their target.

View File

@ -3,7 +3,7 @@ name=Princess
image=human-princess.png image=human-princess.png
hitpoints=48 hitpoints=48
movement_type=elusivefoot movement_type=elusivefoot
movement=7 movement=6
experience=500 experience=500
level=3 level=3
alignment=neutral alignment=neutral
@ -11,7 +11,7 @@ advanceto=null
cost=110 cost=110
ability=leadership ability=leadership
usage=fighter usage=fighter
unit_description="A noble at birth, the princess has learned swordplay with the greatest generals, and battle tatics with the greatest sages, making her both a great combatant and leader. All the units of lower level around the princess will fight better due to her shining presence." unit_description="A noble at birth, the princess has learnt swordplay with the greatest generals, and battle tactics with the greatest sages, making her both a great combatant and leader. The units of lower level around the princess will fight better due to her presence. The princess is also nimble and dextrous, having skills like that of a thief."
[attack] [attack]
name=sword name=sword
type=blade type=blade

BIN
images/cavespider.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 819 B

BIN
images/terrain/cave.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

BIN
images/terrain/cavewall.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

View File

@ -47,7 +47,7 @@ private:
std::string recruit_unit(const gamemap& map, int side, std::string recruit_unit(const gamemap& map, int side,
std::map<gamemap::location,unit>& units, unit& new_unit, std::map<gamemap::location,unit>& units, unit& new_unit,
gamemap::location recruit_location, display* disp) gamemap::location recruit_location, display* disp, bool need_castle)
{ {
typedef std::map<gamemap::location,unit> units_map; typedef std::map<gamemap::location,unit> units_map;
@ -75,7 +75,8 @@ std::string recruit_unit(const gamemap& map, int side,
} }
if(!map.on_board(recruit_location)) { if(!map.on_board(recruit_location)) {
recruit_location = find_vacant_tile(map,units,u->first,gamemap::CASTLE); recruit_location = find_vacant_tile(map,units,u->first,
need_castle ? gamemap::CASTLE : 0);
} }
if(!map.on_board(recruit_location)) { if(!map.on_board(recruit_location)) {
@ -87,7 +88,8 @@ std::string recruit_unit(const gamemap& map, int side,
units.insert(std::pair<gamemap::location,unit>( units.insert(std::pair<gamemap::location,unit>(
recruit_location,new_unit)); recruit_location,new_unit));
if(disp != NULL && !disp->turbo()) { if(disp != NULL && !disp->turbo() &&
!disp->shrouded(recruit_location.x,recruit_location.y)) {
disp->draw(true,true); disp->draw(true,true);
for(double alpha = 0.0; alpha <= 1.0; alpha += 0.1) { for(double alpha = 0.0; alpha <= 1.0; alpha += 0.1) {
@ -328,9 +330,9 @@ void attack(display& gui, const gamemap& map,
hits ? stats.damage_defender_takes : 0, hits ? stats.damage_defender_takes : 0,
a->second.attacks()[attack_with]); a->second.attacks()[attack_with]);
if(dies) { if(dies) {
attackerxp = 10*d->second.type().level(); attackerxp = 8*d->second.type().level();
if(d->second.type().level() == 0) if(d->second.type().level() == 0)
attackerxp = 5; attackerxp = 4;
defenderxp = 0; defenderxp = 0;
@ -386,9 +388,9 @@ void attack(display& gui, const gamemap& map,
d->second.attacks()[stats.defend_with]); d->second.attacks()[stats.defend_with]);
if(dies) { if(dies) {
defenderxp = 10*a->second.type().level(); defenderxp = 8*a->second.type().level();
if(a->second.type().level() == 0) if(a->second.type().level() == 0)
defenderxp = 5; defenderxp = 4;
attackerxp = 0; attackerxp = 0;
@ -583,7 +585,8 @@ void calculate_healing(display& disp, const gamemap& map,
const gamemap::location& loc = h->first; const gamemap::location& loc = h->first;
const bool show_healing = !disp.turbo() && !recorder.skipping(); const bool show_healing = !disp.turbo() && !recorder.skipping() &&
!disp.shrouded(loc.x,loc.y);
assert(units.count(loc) == 1); assert(units.count(loc) == 1);
@ -871,3 +874,53 @@ size_t move_unit(display* disp, const gamemap& map,
return steps.size(); return steps.size();
} }
void clear_shroud_loc(const gamemap& map, team& tm,
const gamemap::location& loc)
{
if(map.on_board(loc))
tm.clear_shroud(loc.x,loc.y);
static gamemap::location adj[6];
get_adjacent_tiles(loc,adj);
for(int i = 0; i != 6; ++i) {
if(map.on_board(adj[i])) {
tm.clear_shroud(adj[i].x,adj[i].y);
}
}
}
void clear_shroud_unit(const gamemap& map, const game_data& gamedata,
const unit_map& units, const gamemap::location& loc,
std::vector<team>& teams, int team)
{
paths p(map,gamedata,units,loc,teams,true,false);
for(paths::routes_map::const_iterator i = p.routes.begin();
i != p.routes.end(); ++i) {
clear_shroud_loc(map,teams[team],i->first);
}
}
bool clear_shroud(display& disp, const gamemap& map, const game_data& gamedata,
const unit_map& units, std::vector<team>& teams, int team)
{
if(teams[team].uses_shroud() == false)
return false;
for(unit_map::const_iterator i = units.begin(); i != units.end(); ++i) {
if(i->second.side() == team+1) {
//we're not really going to mutate the unit, just temporarily
//set its moves to maximum, but then switch them back
unit& mutable_unit = const_cast<unit&>(i->second);
const int old_moves = mutable_unit.movement_left();
mutable_unit.set_movement(mutable_unit.total_movement());
clear_shroud_unit(map,gamedata,units,i->first,teams,team);
mutable_unit.set_movement(old_moves);
}
}
disp.recalculate_minimap();
return true;
}

View File

@ -27,7 +27,7 @@
std::string recruit_unit(const gamemap& map, int team, std::string recruit_unit(const gamemap& map, int team,
std::map<gamemap::location,unit>& units, std::map<gamemap::location,unit>& units,
unit& unit, gamemap::location preferred_location, unit& unit, gamemap::location preferred_location,
display *disp=NULL); display *disp=NULL, bool need_castle=true);
struct battle_stats struct battle_stats
{ {
@ -112,4 +112,7 @@ size_t move_unit(display* disp, const gamemap& map,
const std::vector<gamemap::location>& steps, const std::vector<gamemap::location>& steps,
replay* move_recorder, undo_list* undos); replay* move_recorder, undo_list* undos);
bool clear_shroud(display& disp, const gamemap& map, const game_data& gamedata,
const unit_map& units, std::vector<team>& teams, int team);
#endif #endif

View File

@ -103,7 +103,9 @@ void move_unit(const game_data& gameinfo, display& disp,
paths current_paths = paths(map,gameinfo,units,from,teams, paths current_paths = paths(map,gameinfo,units,from,teams,
ignore_zocs,teleport); ignore_zocs,teleport);
paths_wiper wiper(disp); paths_wiper wiper(disp);
disp.set_paths(&current_paths);
if(!disp.shrouded(from.x,from.y))
disp.set_paths(&current_paths);
disp.scroll_to_tiles(from.x,from.y,to.x,to.y); disp.scroll_to_tiles(from.x,from.y,to.x,to.y);
@ -402,6 +404,9 @@ void do_move(display& disp, const gamemap& map, const game_data& gameinfo,
} }
if(want_tower) { if(want_tower) {
std::cerr << "trying to acquire village: " << i->first.x
<< ", " << i->first.y << "\n";
const std::map<location,unit>::iterator un = units.find(i->second); const std::map<location,unit>::iterator un = units.find(i->second);
if(un == units.end()) { if(un == units.end()) {
assert(false); assert(false);
@ -419,7 +424,6 @@ void do_move(display& disp, const gamemap& map, const game_data& gameinfo,
return; return;
} }
} }
std::cout << "b\n";
//find units in need of healing //find units in need of healing
std::map<location,unit>::iterator u_it = units.begin(); std::map<location,unit>::iterator u_it = units.begin();
@ -430,7 +434,7 @@ void do_move(display& disp, const gamemap& map, const game_data& gameinfo,
//worth of healing, and doesn't regenerate itself, then try to //worth of healing, and doesn't regenerate itself, then try to
//find a vacant village for it to rest in //find a vacant village for it to rest in
if(u.side() == team_num && if(u.side() == team_num &&
u.type().hitpoints() - u.hitpoints() >= game_config::heal_amount/2 && u.type().hitpoints() - u.hitpoints() >= game_config::cure_amount/2 &&
!u.type().regenerates()) { !u.type().regenerates()) {
typedef std::multimap<location,location>::iterator Itor; typedef std::multimap<location,location>::iterator Itor;
std::pair<Itor,Itor> it = srcdst.equal_range(u_it->first); std::pair<Itor,Itor> it = srcdst.equal_range(u_it->first);
@ -440,6 +444,8 @@ void do_move(display& disp, const gamemap& map, const game_data& gameinfo,
units.find(dst) == units.end()) { units.find(dst) == units.end()) {
const location& src = it.first->first; const location& src = it.first->first;
std::cerr << "moving unit to village for healing...\n";
move_unit(gameinfo,disp,map,units,src,dst, move_unit(gameinfo,disp,map,units,src,dst,
possible_moves,teams,team_num); possible_moves,teams,team_num);
do_move(disp,map,gameinfo,units,teams,team_num,state, do_move(disp,map,gameinfo,units,teams,team_num,state,

View File

@ -235,7 +235,7 @@ std::pair<location,location> choose_move(
//now see if any other unit can put a better bid forward //now see if any other unit can put a better bid forward
for(++u; u != units.end(); ++u) { for(++u; u != units.end(); ++u) {
if(u->second.side() != current_team || u->second.can_recruit() || if(u->second.side() != current_team || u->second.can_recruit() ||
u->second.movement_left() <= 0) { u->second.movement_left() <= 0 || u->second.is_guardian()) {
continue; continue;
} }

View File

@ -52,7 +52,7 @@ struct config
const std::vector<line_source>* lines=0); //throws config::error const std::vector<line_source>* lines=0); //throws config::error
std::string write() const; std::string write() const;
std::map<std::string,std::string> values; string_map values;
std::map<std::string,std::vector<config*> > children; std::map<std::string,std::vector<config*> > children;
static std::vector<std::string> split(const std::string& val); static std::vector<std::string> split(const std::string& val);

View File

@ -129,6 +129,10 @@ SDL_Rect display::screen_area() const
void display::select_hex(gamemap::location hex) void display::select_hex(gamemap::location hex)
{ {
if(team_valid() && teams_[currentTeam_].shrouded(hex.x,hex.y)) {
return;
}
invalidate(selectedHex_); invalidate(selectedHex_);
selectedHex_ = hex; selectedHex_ = hex;
invalidate(selectedHex_); invalidate(selectedHex_);
@ -203,13 +207,22 @@ void display::zoom(double amount)
clear_surfaces(brightenedImages_); clear_surfaces(brightenedImages_);
energy_bar_count_ = std::pair<int,int>(-1,-1); energy_bar_count_ = std::pair<int,int>(-1,-1);
const double orig_xpos = xpos_;
const double orig_ypos = ypos_;
xpos_ /= zoom_; xpos_ /= zoom_;
ypos_ /= zoom_; ypos_ /= zoom_;
const double max_zoom = 200.0; const double max_zoom = 200.0;
const double orig_zoom = zoom_;
zoom_ += amount; zoom_ += amount;
if(zoom_ > max_zoom) if(zoom_ > max_zoom) {
zoom_ = max_zoom; zoom_ = orig_zoom;
xpos_ = orig_xpos;
ypos_ = orig_ypos;
return;
}
xpos_ *= zoom_; xpos_ *= zoom_;
ypos_ *= zoom_; ypos_ *= zoom_;
@ -217,8 +230,17 @@ void display::zoom(double amount)
xpos_ += amount*2; xpos_ += amount*2;
ypos_ += amount*2; ypos_ += amount*2;
const double prev_zoom = zoom_;
bounds_check_position(); bounds_check_position();
if(zoom_ != prev_zoom) {
xpos_ = orig_xpos;
ypos_ = orig_ypos;
zoom_ = orig_zoom;
return;
}
invalidate_all(); invalidate_all();
} }
@ -229,7 +251,7 @@ void display::default_zoom()
void display::scroll_to_tile(int x, int y, SCROLL_TYPE scroll_type) void display::scroll_to_tile(int x, int y, SCROLL_TYPE scroll_type)
{ {
if(update_locked()) if(update_locked() || shrouded(x,y))
return; return;
const double xpos = static_cast<double>(x)*zoom_*0.75 - xpos_; const double xpos = static_cast<double>(x)*zoom_*0.75 - xpos_;
@ -440,7 +462,7 @@ void display::draw_sidebar()
i = units_.find(selectedHex_); i = units_.find(selectedHex_);
if(i != units_.end()) if(i != units_.end())
draw_unit_details(mapx()+2,int(390*sidebarScaling_),selectedHex_, draw_unit_details(mapx()+2,int(400*sidebarScaling_),selectedHex_,
i->second,unitDescriptionRect_,unitProfileRect_); i->second,unitDescriptionRect_,unitProfileRect_);
invalidateUnit_ = false; invalidateUnit_ = false;
} }
@ -494,21 +516,29 @@ void display::draw_game_status(int x, int y)
int nunits = 0; int nunits = 0;
for(std::map<gamemap::location,unit>::const_iterator uit = units_.begin(); for(std::map<gamemap::location,unit>::const_iterator uit = units_.begin();
uit != units_.end(); ++uit) { uit != units_.end(); ++uit) {
if(uit->second.side() == currentTeam_+1) { if(size_t(uit->second.side()) == currentTeam_+1) {
++nunits; ++nunits;
} }
} }
const int income = teams_[currentTeam_].income() - nunits;
std::stringstream details; std::stringstream details;
details << string_table["turn"] << ": " << status_.turn() << "/"
<< status_.number_of_turns() << "\n" << string_table["gold"] << ": " if(team_valid()) {
<< teams_[currentTeam_].gold() << "\n" const int upkeep = team_upkeep(units_,currentTeam_+1);
<< string_table["villages"] << ": "
<< teams_[currentTeam_].towers().size() << "\n" const int expenses = upkeep - teams_[currentTeam_].towers().size();
<< string_table["units"] << ": " << nunits << "\n" const int income = teams_[currentTeam_].income() - maximum(expenses,0);
<< string_table["income"] << ": " << income << "\n";
details << string_table["turn"] << ": " << status_.turn() << "/"
<< status_.number_of_turns() << "\n"
<< string_table["gold"] << ": "
<< teams_[currentTeam_].gold() << "\n"
<< string_table["villages"] << ": "
<< teams_[currentTeam_].towers().size() << "\n"
<< string_table["units"] << ": " << nunits << "\n"
<< string_table["upkeep"] << ": " << upkeep << "\n"
<< string_table["income"] << ": " << income << "\n";
}
if(map_.on_board(mouseoverHex_)) { if(map_.on_board(mouseoverHex_)) {
const gamemap::TERRAIN terrain = map_[mouseoverHex_.x][mouseoverHex_.y]; const gamemap::TERRAIN terrain = map_[mouseoverHex_.x][mouseoverHex_.y];
@ -860,10 +890,12 @@ void display::draw_tile(int x, int y, SDL_Surface* unit_image,
const int se_xpos = (int)get_location_x(se_loc); const int se_xpos = (int)get_location_x(se_loc);
const int se_ypos = (int)get_location_y(se_loc); const int se_ypos = (int)get_location_y(se_loc);
const bool is_shrouded = shrouded(x,y);
gamemap::TERRAIN terrain = gamemap::VOID_TERRAIN; gamemap::TERRAIN terrain = gamemap::VOID_TERRAIN;
if(x >= 0 && y >= 0 && x < map_.x() && y < map_.y()) if(map_.on_board(loc) && !is_shrouded) {
terrain = map_[x][y]; terrain = map_[x][y];
}
IMAGE_TYPE image_type = SCALED; IMAGE_TYPE image_type = SCALED;
@ -887,14 +919,23 @@ void display::draw_tile(int x, int y, SDL_Surface* unit_image,
return; return;
} }
std::vector<SDL_Surface*> overlaps = getAdjacentTerrain(x,y,image_type); std::vector<SDL_Surface*> overlaps;
typedef std::multimap<gamemap::location,std::string>::const_iterator Itor;
for(std::pair<Itor,Itor> overlays = if(!is_shrouded) {
overlays_.equal_range(gamemap::location(x,y)); overlaps = getAdjacentTerrain(x,y,image_type);
overlays.first != overlays.second; ++overlays.first) {
SDL_Surface* const overlay_surface = getImage(overlays.first->second); typedef std::multimap<gamemap::location,std::string>::const_iterator
if(overlay_surface != NULL) { Itor;
overlaps.push_back(overlay_surface);
for(std::pair<Itor,Itor> overlays =
overlays_.equal_range(gamemap::location(x,y));
overlays.first != overlays.second; ++overlays.first) {
SDL_Surface* const overlay_surface =
getImage(overlays.first->second);
if(overlay_surface != NULL) {
overlaps.push_back(overlay_surface);
}
} }
} }
@ -939,8 +980,9 @@ void display::draw_tile(int x, int y, SDL_Surface* unit_image,
const char* energy_file = NULL; const char* energy_file = NULL;
if(it->second.side() != currentTeam_+1) { if(size_t(it->second.side()) != currentTeam_+1) {
if(teams_[currentTeam_].is_enemy(it->second.side())) { if(team_valid() &&
teams_[currentTeam_].is_enemy(it->second.side())) {
energy_file = "enemy-energy.png"; energy_file = "enemy-energy.png";
} else { } else {
energy_file = "ally-energy.png"; energy_file = "ally-energy.png";
@ -1118,7 +1160,7 @@ void display::draw_tile(int x, int y, SDL_Surface* unit_image,
debugHighlights_[gamemap::location(x,y)],0); debugHighlights_[gamemap::location(x,y)],0);
} }
if(unit_image == NULL || energy_image == NULL) if(unit_image == NULL || energy_image == NULL || is_shrouded)
return; return;
if(loc != hiddenUnit_) { if(loc != hiddenUnit_) {
@ -1527,8 +1569,11 @@ SDL_Surface* display::getMinimap(int w, int h)
for(int y = 0; y != map_.y(); ++y) { for(int y = 0; y != map_.y(); ++y) {
for(int x = 0; x != map_.x(); ++x) { for(int x = 0; x != map_.x(); ++x) {
*data = map_.get_terrain_info(map_[x][y]).get_rgb(). if(shrouded(x,y))
format(surface->format); *data = 0;
else
*data = map_.get_terrain_info(map_[x][y]).get_rgb().
format(surface->format);
++data; ++data;
} }
@ -1600,6 +1645,9 @@ bool display::unit_attack_ranged(const gamemap::location& a,
const gamemap::location& b, int damage, const gamemap::location& b, int damage,
const attack_type& attack) const attack_type& attack)
{ {
const bool hide = update_locked() || shrouded(a.x,a.y) && shrouded(b.x,b.y);
const unit_map::iterator att = units_.find(a);
const unit_map::iterator def = units_.find(b); const unit_map::iterator def = units_.find(b);
def->second.set_defending(true,attack_type::LONG_RANGE); def->second.set_defending(true,attack_type::LONG_RANGE);
@ -1648,7 +1696,7 @@ bool display::unit_attack_ranged(const gamemap::location& a,
//this is a while instead of an if, because there might be multiple //this is a while instead of an if, because there might be multiple
//sounds playing simultaneously or close together //sounds playing simultaneously or close together
while(!update_locked() && sfx_it != sounds.end() && i >= sfx_it->time) { while(!hide && sfx_it != sounds.end() && i >= sfx_it->time) {
const std::string& sfx = hits ? sfx_it->on_hit : sfx_it->on_miss; const std::string& sfx = hits ? sfx_it->on_hit : sfx_it->on_miss;
if(sfx.empty() == false) { if(sfx.empty() == false) {
sound::play_sound(hits ? sfx_it->on_hit : sfx_it->on_miss); sound::play_sound(hits ? sfx_it->on_hit : sfx_it->on_miss);
@ -1657,9 +1705,14 @@ bool display::unit_attack_ranged(const gamemap::location& a,
++sfx_it; ++sfx_it;
} }
const std::string* const unit_image = attack.get_frame(i); const std::string* unit_image = attack.get_frame(i);
if(!update_locked()) { if(unit_image == NULL) {
unit_image =
&att->second.type().image_fighting(attack_type::LONG_RANGE);
}
if(!hide) {
SDL_Surface* const image = (unit_image == NULL) ? SDL_Surface* const image = (unit_image == NULL) ?
NULL : getImage(*unit_image); NULL : getImage(*unit_image);
draw_tile(a.x,a.y,image); draw_tile(a.x,a.y,image);
@ -1692,7 +1745,7 @@ bool display::unit_attack_ranged(const gamemap::location& a,
draw_tile(b.x,b.y,NULL,defensive_alpha,defensive_colour); draw_tile(b.x,b.y,NULL,defensive_alpha,defensive_colour);
if(i >= 0 && i < real_last_missile && !update_locked()) { if(i >= 0 && i < real_last_missile && !hide) {
const int missile_frame = i + first_missile; const int missile_frame = i + first_missile;
const std::string* missile_image const std::string* missile_image
@ -1721,7 +1774,7 @@ bool display::unit_attack_ranged(const gamemap::location& a,
} }
const int wait_time = ticks + time_resolution - SDL_GetTicks(); const int wait_time = ticks + time_resolution - SDL_GetTicks();
if(wait_time > 0 && !turbo() && !update_locked()) if(wait_time > 0 && !turbo() && !hide)
SDL_Delay(wait_time); SDL_Delay(wait_time);
ticks = SDL_GetTicks(); ticks = SDL_GetTicks();
@ -1740,7 +1793,7 @@ bool display::unit_attack_ranged(const gamemap::location& a,
void display::unit_die(const gamemap::location& loc, SDL_Surface* image) void display::unit_die(const gamemap::location& loc, SDL_Surface* image)
{ {
if(update_locked()) if(update_locked() || shrouded(loc.x,loc.y))
return; return;
const int frame_time = 30; const int frame_time = 30;
@ -1764,6 +1817,8 @@ bool display::unit_attack(const gamemap::location& a,
const gamemap::location& b, int damage, const gamemap::location& b, int damage,
const attack_type& attack) const attack_type& attack)
{ {
const bool hide = update_locked() || shrouded(a.x,a.y) && shrouded(b.x,b.y);
log_scope("unit_attack"); log_scope("unit_attack");
invalidate_all(); invalidate_all();
draw(true,true); draw(true,true);
@ -1823,7 +1878,7 @@ bool display::unit_attack(const gamemap::location& a,
//this is a while instead of an if, because there might be multiple //this is a while instead of an if, because there might be multiple
//sounds playing simultaneously or close together //sounds playing simultaneously or close together
while(!update_locked() && sfx_it != sounds.end() && i >= sfx_it->time) { while(!hide && sfx_it != sounds.end() && i >= sfx_it->time) {
const std::string& sfx = hits ? sfx_it->on_hit : sfx_it->on_miss; const std::string& sfx = hits ? sfx_it->on_hit : sfx_it->on_miss;
if(sfx.empty() == false) { if(sfx.empty() == false) {
sound::play_sound(hits ? sfx_it->on_hit : sfx_it->on_miss); sound::play_sound(hits ? sfx_it->on_hit : sfx_it->on_miss);
@ -1874,11 +1929,11 @@ bool display::unit_attack(const gamemap::location& a,
const int posx = int(pos*xsrc + (1.0-pos)*xdst) + xoffset; const int posx = int(pos*xsrc + (1.0-pos)*xdst) + xoffset;
const int posy = int(pos*ysrc + (1.0-pos)*ydst); const int posy = int(pos*ysrc + (1.0-pos)*ydst);
if(image != NULL && !update_locked()) if(image != NULL && !hide)
draw_unit(posx,posy,image,attacker.facing_left()); draw_unit(posx,posy,image,attacker.facing_left());
const int wait_time = ticks + time_resolution - SDL_GetTicks(); const int wait_time = ticks + time_resolution - SDL_GetTicks();
if(wait_time > 0 && !turbo() && !update_locked()) if(wait_time > 0 && !turbo() && !hide)
SDL_Delay(wait_time); SDL_Delay(wait_time);
ticks = SDL_GetTicks(); ticks = SDL_GetTicks();
@ -1900,7 +1955,9 @@ void display::move_unit_between(const gamemap::location& a,
const gamemap::location& b, const gamemap::location& b,
const unit& u) const unit& u)
{ {
if(update_locked()) if(update_locked() || team_valid()
&& teams_[currentTeam_].shrouded(a.x,a.y)
&& teams_[currentTeam_].shrouded(b.x,b.y))
return; return;
const bool face_left = u.facing_left(); const bool face_left = u.facing_left();
@ -2060,12 +2117,17 @@ void display::draw_unit(int x, int y, SDL_Surface* image,
surface_lock screen_lock(screen); surface_lock screen_lock(screen);
const Pixel ShroudColour = 0;
for(; y != endy; ++y, src += src_increment) { for(; y != endy; ++y, src += src_increment) {
Pixel* dst = screen_lock.pixels() + y*screen->w + x; Pixel* dst = screen_lock.pixels() + y*screen->w + x;
if(alpha == 1.0) { if(alpha == 1.0) {
if(reverse) { if(reverse) {
for(int i = xoffset; i != len; ++i) { for(int i = xoffset; i != len; ++i) {
if(dst[i-xoffset] == ShroudColour)
continue;
if(src[i] == semi_trans) if(src[i] == semi_trans)
dst[i-xoffset] = alpha_blend_pixels( dst[i-xoffset] = alpha_blend_pixels(
0,dst[i-xoffset],fmt,0.5); 0,dst[i-xoffset],fmt,0.5);
@ -2074,6 +2136,9 @@ void display::draw_unit(int x, int y, SDL_Surface* image,
} }
} else { } else {
for(int i = image->w-1-xoffset; i != image->w-len-1; --i,++dst){ for(int i = image->w-1-xoffset; i != image->w-len-1; --i,++dst){
if(*dst == ShroudColour)
continue;
if(src[i] == semi_trans) if(src[i] == semi_trans)
*dst = alpha_blend_pixels(0,*dst,fmt,0.5); *dst = alpha_blend_pixels(0,*dst,fmt,0.5);
else if(src[i] != 0) else if(src[i] != 0)
@ -2083,6 +2148,9 @@ void display::draw_unit(int x, int y, SDL_Surface* image,
} else { } else {
if(reverse) { if(reverse) {
for(int i = xoffset; i != len; ++i) { for(int i = xoffset; i != len; ++i) {
if(dst[i-xoffset] == ShroudColour)
continue;
const Pixel blend = blendto ? blendto : dst[i-xoffset]; const Pixel blend = blendto ? blendto : dst[i-xoffset];
if(src[i] != 0) if(src[i] != 0)
@ -2091,6 +2159,9 @@ void display::draw_unit(int x, int y, SDL_Surface* image,
} }
} else { } else {
for(int i = image->w-1-xoffset; i != image->w-len-1; --i,++dst){ for(int i = image->w-1-xoffset; i != image->w-len-1; --i,++dst){
if(*dst == ShroudColour)
continue;
const Pixel blend = blendto ? blendto : *dst; const Pixel blend = blendto ? blendto : *dst;
if(src[i] != 0) if(src[i] != 0)
*dst = alpha_blend_pixels(src[i],blend,fmt,alpha); *dst = alpha_blend_pixels(src[i],blend,fmt,alpha);
@ -2172,8 +2243,9 @@ void display::remove_overlay(const gamemap::location& loc)
overlays_.erase(loc); overlays_.erase(loc);
} }
void display::set_team(int team) void display::set_team(size_t team)
{ {
assert(team < teams_.size());
currentTeam_ = team; currentTeam_ = team;
} }
@ -2226,3 +2298,16 @@ void display::clear_debug_highlights()
{ {
debugHighlights_.clear(); debugHighlights_.clear();
} }
bool display::shrouded(int x, int y) const
{
if(team_valid())
return teams_[currentTeam_].shrouded(x,y);
else
return false;
}
bool display::team_valid() const
{
return currentTeam_ < teams_.size();
}

View File

@ -102,7 +102,7 @@ public:
void draw_terrain_palette(int x, int y, gamemap::TERRAIN selected); void draw_terrain_palette(int x, int y, gamemap::TERRAIN selected);
gamemap::TERRAIN get_terrain_on(int palx, int paly, int x, int y); gamemap::TERRAIN get_terrain_on(int palx, int paly, int x, int y);
void set_team(int team); void set_team(size_t team);
void set_advancing_unit(const gamemap::location& loc, double amount); void set_advancing_unit(const gamemap::location& loc, double amount);
@ -117,6 +117,8 @@ public:
static void debug_highlight(const gamemap::location& loc, double amount); static void debug_highlight(const gamemap::location& loc, double amount);
static void clear_debug_highlights(); static void clear_debug_highlights();
bool shrouded(int x, int y) const;
private: private:
display(const display&); display(const display&);
void operator=(const display&); void operator=(const display&);
@ -182,6 +184,8 @@ private:
const gamestatus& status_; const gamestatus& status_;
bool team_valid() const;
const std::vector<team>& teams_; const std::vector<team>& teams_;
int lastDraw_; int lastDraw_;
@ -200,7 +204,7 @@ private:
bool sideBarBgDrawn_; bool sideBarBgDrawn_;
int lastTimeOfDay_; int lastTimeOfDay_;
int currentTeam_; size_t currentTeam_;
//used to store a unit that is not drawn, because it's currently //used to store a unit that is not drawn, because it's currently
//being moved or otherwise changed //being moved or otherwise changed

View File

@ -118,7 +118,7 @@ SDL_Rect draw_text_line(display* gui, const SDL_Rect& area, int size,
return res; return res;
} }
SDL_Surface* const surface = TTF_RenderText_Blended(font,text.c_str(),col); scoped_sdl_surface surface(TTF_RenderText_Blended(font,text.c_str(),col));
if(surface == NULL) { if(surface == NULL) {
std::cerr << "Could not render ttf: '" << text << "'\n"; std::cerr << "Could not render ttf: '" << text << "'\n";
SDL_Rect res; SDL_Rect res;
@ -147,8 +147,6 @@ SDL_Rect draw_text_line(display* gui, const SDL_Rect& area, int size,
SDL_BlitSurface(surface,&src,gui->video().getSurface(),&dest); SDL_BlitSurface(surface,&src,gui->video().getSurface(),&dest);
} }
SDL_FreeSurface(surface);
return dest; return dest;
} }

View File

@ -142,10 +142,7 @@ LEVEL_RESULT play_game(display& disp, game_state& state, config& game_config,
int play_game(int argc, char** argv) int play_game(int argc, char** argv)
{ {
std::string text_chr = read_file("data/text.chr"); CVideo video;
text_chr.resize(256*8);
CVideo video(text_chr.c_str());
const font::manager font_manager; const font::manager font_manager;
const sound::manager sound_manager; const sound::manager sound_manager;
const preferences::manager prefs_manager; const preferences::manager prefs_manager;

View File

@ -16,12 +16,12 @@ namespace game_config
{ {
const int unit_cost = 1; const int unit_cost = 1;
const int base_income = 2; const int base_income = 2;
const int tower_income = 2; const int tower_income = 1;
const int heal_amount = 4; const int heal_amount = 4;
const int healer_heals_per_turn = 8; const int healer_heals_per_turn = 8;
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.4.8"; const std::string version = "0.4.9-CVS";
bool debug = false; bool debug = false;
} }

View File

@ -15,6 +15,7 @@
#include "language.hpp" #include "language.hpp"
#include "playlevel.hpp" #include "playlevel.hpp"
#include "replay.hpp" #include "replay.hpp"
#include "sound.hpp"
#include <cstdlib> #include <cstdlib>
#include <deque> #include <deque>
@ -55,8 +56,8 @@ bool conditional_passed(game_state& state_of_game,
std::vector<config*>& variables = cond.children["variable"]; std::vector<config*>& variables = cond.children["variable"];
for(std::vector<config*>::iterator var = variables.begin(); for(std::vector<config*>::iterator var = variables.begin();
var != variables.end(); ++var) { var != variables.end(); ++var) {
std::map<std::string,std::string>& values = (*var)->values; string_map& values = (*var)->values;
std::map<std::string,std::string>& vars = state_of_game.variables; string_map& vars = state_of_game.variables;
const std::string& name = values["name"]; const std::string& name = values["name"];
//if we don't have a record of the variable, then the statement //if we don't have a record of the variable, then the statement
@ -74,7 +75,7 @@ bool conditional_passed(game_state& state_of_game,
const std::string& value = vars[name]; const std::string& value = vars[name];
const double num_value = atof(value.c_str()); const double num_value = atof(value.c_str());
std::map<std::string,std::string>::iterator itor; string_map::iterator itor;
itor = values.find("equals"); itor = values.find("equals");
if(itor != values.end() && itor->second != value) { if(itor != values.end() && itor->second != value) {
@ -127,6 +128,7 @@ namespace {
display* screen = NULL; display* screen = NULL;
gamemap* game_map = NULL; gamemap* game_map = NULL;
std::map<gamemap::location,unit>* units = NULL; std::map<gamemap::location,unit>* units = 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;
@ -191,11 +193,32 @@ void event_handler::handle_event(const queued_event& event_info, config* cfg)
handle_event(event_info,*cmd); handle_event(event_info,*cmd);
} }
//sounds
std::vector<config*>& sounds = cfg->children["sound"];
for(std::vector<config*>::iterator sfx = sounds.begin();
sfx != sounds.end(); ++sfx) {
sound::play_sound((*sfx)->values["name"]);
}
//an award of gold to a particular side
std::vector<config*>& gold = cfg->children["gold"];
for(std::vector<config*>::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 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;
if(team_index < teams->size()) {
(*teams)[team_index].spend_gold(-amount_num);
}
}
//setting a variable //setting a variable
std::vector<config*>& set_vars = cfg->children["set_variable"]; std::vector<config*>& set_vars = cfg->children["set_variable"];
for(std::vector<config*>::iterator var = set_vars.begin(); for(std::vector<config*>::iterator var = set_vars.begin();
var != set_vars.end(); ++var) { var != set_vars.end(); ++var) {
std::map<std::string,std::string>& vals = (*var)->values; string_map& vals = (*var)->values;
const std::string& name = vals["name"]; const std::string& name = vals["name"];
const std::string& value = vals["value"]; const std::string& value = vals["value"];
if(value.empty() == false) { if(value.empty() == false) {
@ -341,7 +364,8 @@ void event_handler::handle_event(const queued_event& event_info, config* cfg)
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(**ir)) { if(u->matches_filter(**ir)) {
recruit_unit(*game_map,1,*units,*u,gamemap::location(),screen); recruit_unit(*game_map,1,*units,*u,gamemap::location(),
screen,false);
u = avail.erase(u); u = avail.erase(u);
if(u == avail.end()) if(u == avail.end())
break; break;
@ -352,7 +376,7 @@ void event_handler::handle_event(const queued_event& event_info, config* cfg)
std::vector<config*>& objects = cfg->children["object"]; std::vector<config*>& objects = cfg->children["object"];
for(std::vector<config*>::iterator obj = objects.begin(); for(std::vector<config*>::iterator obj = objects.begin();
obj != objects.end(); ++obj) { obj != objects.end(); ++obj) {
std::map<std::string,std::string>& values = (*obj)->values; string_map& values = (*obj)->values;
//if this item has already been used //if this item has already been used
if(values["used"].empty() == false) if(values["used"].empty() == false)
@ -414,7 +438,8 @@ void event_handler::handle_event(const queued_event& event_info, config* cfg)
std::vector<config*>& messages = cfg->children["message"]; std::vector<config*>& messages = cfg->children["message"];
for(std::vector<config*>::iterator msg = messages.begin(); for(std::vector<config*>::iterator msg = messages.begin();
msg != messages.end(); ++msg) { msg != messages.end(); ++msg) {
std::map<std::string,std::string>& values = (*msg)->values; 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") {
speaker = units->find(event_info.loc1); speaker = units->find(event_info.loc1);
@ -434,6 +459,11 @@ 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& id = values["id"]; const std::string& id = values["id"];
std::string image = (*msg)->values["image"]; std::string image = (*msg)->values["image"];
@ -665,6 +695,7 @@ namespace game_events {
manager::manager(config& cfg, display& gui_, gamemap& map_, manager::manager(config& cfg, display& gui_, gamemap& map_,
std::map<gamemap::location,unit>& units_, std::map<gamemap::location,unit>& units_,
std::vector<team>& teams_,
game_state& state_of_game_, game_data& game_data_) game_state& state_of_game_, game_data& game_data_)
{ {
std::vector<config*>& events_list = cfg.children["event"]; std::vector<config*>& events_list = cfg.children["event"];
@ -675,6 +706,7 @@ manager::manager(config& cfg, display& gui_, gamemap& map_,
new_handler.name(), new_handler)); new_handler.name(), new_handler));
} }
teams = &teams_;
screen = &gui_; screen = &gui_;
game_map = &map_; game_map = &map_;
units = &units_; units = &units_;

View File

@ -17,6 +17,7 @@
#include "display.hpp" #include "display.hpp"
#include "gamestatus.hpp" #include "gamestatus.hpp"
#include "map.hpp" #include "map.hpp"
#include "team.hpp"
#include "unit.hpp" #include "unit.hpp"
#include "unit_types.hpp" #include "unit_types.hpp"
@ -31,7 +32,7 @@ bool conditional_passed(game_state& state_of_game,
struct manager { struct manager {
manager(config& cfg, display& disp, gamemap& map, manager(config& cfg, display& disp, gamemap& map,
std::map<gamemap::location,unit>& units, std::map<gamemap::location,unit>& units, std::vector<team>& teams,
game_state& state_of_game, game_data& data); game_state& state_of_game, game_data& data);
~manager(); ~manager();
}; };

View File

@ -45,6 +45,7 @@ HOTKEY_COMMAND string_to_command(const std::string& str)
m.insert(val("save",HOTKEY_SAVE_GAME)); m.insert(val("save",HOTKEY_SAVE_GAME));
m.insert(val("recruit",HOTKEY_RECRUIT)); m.insert(val("recruit",HOTKEY_RECRUIT));
m.insert(val("recall",HOTKEY_RECALL)); m.insert(val("recall",HOTKEY_RECALL));
m.insert(val("endturn",HOTKEY_ENDTURN));
} }
const std::map<std::string,HOTKEY_COMMAND>::const_iterator i = m.find(str); const std::map<std::string,HOTKEY_COMMAND>::const_iterator i = m.find(str);

View File

@ -23,7 +23,7 @@ enum HOTKEY_COMMAND { HOTKEY_CYCLE_UNITS, HOTKEY_END_UNIT_TURN, HOTKEY_LEADER,
HOTKEY_FULLSCREEN, HOTKEY_ACCELERATED, HOTKEY_FULLSCREEN, HOTKEY_ACCELERATED,
HOTKEY_TERRAIN_TABLE, HOTKEY_ATTACK_RESISTANCE, HOTKEY_TERRAIN_TABLE, HOTKEY_ATTACK_RESISTANCE,
HOTKEY_UNIT_DESCRIPTION, HOTKEY_SAVE_GAME, HOTKEY_UNIT_DESCRIPTION, HOTKEY_SAVE_GAME,
HOTKEY_RECRUIT, HOTKEY_RECALL, HOTKEY_RECRUIT, HOTKEY_RECALL, HOTKEY_ENDTURN,
HOTKEY_NULL }; HOTKEY_NULL };
void add_hotkeys(config& cfg); void add_hotkeys(config& cfg);

View File

@ -250,7 +250,7 @@ shortest_path_calculator::shortest_path_calculator(const unit& u, const team& t,
double shortest_path_calculator::cost(const gamemap::location& loc, double shortest_path_calculator::cost(const gamemap::location& loc,
double so_far) const double so_far) const
{ {
if(!map_.on_board(loc)) if(!map_.on_board(loc) || team_.shrouded(loc.x,loc.y))
return 100000.0; return 100000.0;
const unit_map::const_iterator enemy_unit = units_.find(loc); const unit_map::const_iterator enemy_unit = units_.find(loc);

View File

@ -51,7 +51,8 @@ struct paths
int move_left; int move_left;
}; };
std::map<gamemap::location,route> routes; typedef std::map<gamemap::location,route> routes_map;
routes_map routes;
}; };
struct shortest_path_calculator struct shortest_path_calculator

View File

@ -32,8 +32,7 @@ LEVEL_RESULT play_level(game_data& gameinfo, config& terrain_config,
gamemap map(terrain_config,read_file("data/maps/" + level->values["map"])); gamemap map(terrain_config,read_file("data/maps/" + level->values["map"]));
CKey key; CKey key;
typedef std::map<gamemap::location,unit> units_map; unit_map units;
units_map units;
std::vector<team> teams; std::vector<team> teams;
@ -99,7 +98,7 @@ LEVEL_RESULT play_level(game_data& gameinfo, config& terrain_config,
sound::play_music(music); sound::play_music(music);
} }
game_events::manager events_manager(*level,gui,map,units, game_events::manager events_manager(*level,gui,map,units,teams,
state_of_game,gameinfo); state_of_game,gameinfo);
//find a list of 'items' (i.e. overlays) on the level, and add them //find a list of 'items' (i.e. overlays) on the level, and add them
@ -110,7 +109,7 @@ LEVEL_RESULT play_level(game_data& gameinfo, config& terrain_config,
(*overlay)->values["image"]); (*overlay)->values["image"]);
} }
for(units_map::iterator i = units.begin(); i != units.end(); ++i) { for(unit_map::iterator i = units.begin(); i != units.end(); ++i) {
i->second.new_turn(); i->second.new_turn();
} }
@ -124,6 +123,8 @@ LEVEL_RESULT play_level(game_data& gameinfo, config& terrain_config,
try { try {
if(first_time) { if(first_time) {
clear_shroud(gui,map,gameinfo,units,teams,0);
update_locker lock_display(gui,recorder.skipping()); update_locker lock_display(gui,recorder.skipping());
game_events::fire("start"); game_events::fire("start");
gui.draw(); gui.draw();
@ -135,10 +136,12 @@ LEVEL_RESULT play_level(game_data& gameinfo, config& terrain_config,
team_it != teams.end(); ++team_it) { team_it != teams.end(); ++team_it) {
const int player_number = (team_it - teams.begin()) + 1; const int player_number = (team_it - teams.begin()) + 1;
clear_shroud(gui,map,gameinfo,units,teams,player_number-1);
calculate_healing(gui,map,units,player_number); calculate_healing(gui,map,units,player_number);
//scroll the map to the leader //scroll the map to the leader
const units_map::iterator leader = const unit_map::iterator leader =
find_leader(units,player_number); find_leader(units,player_number);
if(leader != units.end() && !recorder.skipping()) { if(leader != units.end() && !recorder.skipping()) {
@ -175,7 +178,7 @@ LEVEL_RESULT play_level(game_data& gameinfo, config& terrain_config,
SDL_Delay(1000); SDL_Delay(1000);
} }
for(units_map::iterator uit = units.begin(); for(unit_map::iterator uit = units.begin();
uit != units.end(); ++uit) { uit != units.end(); ++uit) {
if(uit->second.side() == player_number) if(uit->second.side() == player_number)
uit->second.end_turn(); uit->second.end_turn();
@ -206,18 +209,25 @@ LEVEL_RESULT play_level(game_data& gameinfo, config& terrain_config,
} }
std::map<int,int> expenditure; std::map<int,int> expenditure;
for(units_map::iterator i = units.begin(); for(unit_map::iterator i = units.begin();
i != units.end(); ++i) { i != units.end(); ++i) {
i->second.new_turn(); i->second.new_turn();
expenditure[i->second.side()]++;
} }
int team_num = 1; int team_num = 1;
for(std::vector<team>::iterator it = teams.begin(); for(std::vector<team>::iterator it = teams.begin();
it != teams.end(); ++it, ++team_num) { it != teams.end(); ++it, ++team_num) {
it->new_turn(); it->new_turn();
it->spend_gold(expenditure[team_num]);
//if the expense is less than the number of villages owned,
//then we don't have to pay anything at all
const int expense = team_upkeep(units,team_num) -
it->towers().size();
if(expense > 0) {
it->spend_gold(expense);
}
} }
} catch(end_level_exception& end_level) { } catch(end_level_exception& end_level) {
if(end_level.result == QUIT || end_level.result == REPLAY) { if(end_level.result == QUIT || end_level.result == REPLAY) {
@ -255,7 +265,7 @@ LEVEL_RESULT play_level(game_data& gameinfo, config& terrain_config,
const int turns_left = status.number_of_turns() - status.turn(); const int turns_left = status.number_of_turns() - status.turn();
const int finishing_bonus = end_level.gold_bonus ? const int finishing_bonus = end_level.gold_bonus ?
(finishing_bonus_per_turn * turns_left) : 0; (finishing_bonus_per_turn * turns_left) : 0;
state_of_game.gold = (remaining_gold+finishing_bonus)/2; state_of_game.gold = ((remaining_gold+finishing_bonus)*80)/100;
gui::show_dialog(gui,NULL,string_table["victory_heading"], gui::show_dialog(gui,NULL,string_table["victory_heading"],
string_table["victory_message"],gui::OK_ONLY); string_table["victory_message"],gui::OK_ONLY);

View File

@ -179,6 +179,12 @@ void play_turn(game_data& gameinfo, game_state& state_of_game,
unit_map::iterator u = units.find(selected_hex); unit_map::iterator u = units.find(selected_hex);
//if the unit is selected and then itself clicked on,
//any goto command is cancelled
if(selected_hex == hex && u->second.side() == team_num) {
u->second.set_goto(gamemap::location());
}
//if we can move to that tile //if we can move to that tile
std::map<gamemap::location,paths::route>::const_iterator std::map<gamemap::location,paths::route>::const_iterator
route = enemy_paths ? current_paths.routes.end() : route = enemy_paths ? current_paths.routes.end() :
@ -229,13 +235,13 @@ void play_turn(game_data& gameinfo, game_state& state_of_game,
att << attack_name << " (" << attack_type att << attack_name << " (" << attack_type
<< ") " << stats.damage_defender_takes << "-" << ") " << stats.damage_defender_takes << "-"
<< stats.nattacks << " " << range << " " << stats.nattacks << " " << range << " "
<< int(ceil(100.0*stats.chance_to_hit_defender)) << "%"; << int(round(100.0*stats.chance_to_hit_defender))<< "%";
att << "," << string_table["versus"] << ","; att << "," << string_table["versus"] << ",";
att << defend_name << " (" << defend_type att << defend_name << " (" << defend_type
<< ") " << stats.damage_attacker_takes << "-" << ") " << stats.damage_attacker_takes << "-"
<< stats.ndefends << " " << stats.ndefends << " "
<< int(ceil(100.0*stats.chance_to_hit_attacker)) << "%"; << int(round(100.0*stats.chance_to_hit_attacker))<< "%";
items.push_back(att.str()); items.push_back(att.str());
units_list.push_back(enemy->second); units_list.push_back(enemy->second);
@ -307,6 +313,7 @@ void play_turn(game_data& gameinfo, game_state& state_of_game,
const size_t moves = move_unit(&gui,map,units,teams, const size_t moves = move_unit(&gui,map,units,teams,
current_route.steps,&recorder,&undo_stack); current_route.steps,&recorder,&undo_stack);
redo_stack.clear(); redo_stack.clear();
selected_hex = gamemap::location(); selected_hex = gamemap::location();
@ -341,6 +348,9 @@ void play_turn(game_data& gameinfo, game_state& state_of_game,
gui.set_paths(&current_paths); gui.set_paths(&current_paths);
} }
if(clear_shroud(gui,map,gameinfo,units,teams,team_num-1)) {
undo_stack.clear();
}
} else { } else {
gui.set_paths(NULL); gui.set_paths(NULL);
current_paths = paths(); current_paths = paths();
@ -411,9 +421,7 @@ void play_turn(game_data& gameinfo, game_state& state_of_game,
} }
else if(result == string_table["end_turn"]) { else if(result == string_table["end_turn"]) {
recorder.save_game(gameinfo,string_table["auto_save"]); command = HOTKEY_ENDTURN;
recorder.end_turn();
return;
} }
else if(result == string_table["scenario_objectives"]) { else if(result == string_table["scenario_objectives"]) {
@ -484,6 +492,12 @@ void play_turn(game_data& gameinfo, game_state& state_of_game,
if(command == HOTKEY_NULL) if(command == HOTKEY_NULL)
command = check_keys(gui); command = check_keys(gui);
if(command == HOTKEY_ENDTURN) {
recorder.save_game(gameinfo,string_table["auto_save"]);
recorder.end_turn();
return;
}
if(command == HOTKEY_RECRUIT) { if(command == HOTKEY_RECRUIT) {
std::vector<unit> sample_units; std::vector<unit> sample_units;
@ -679,10 +693,15 @@ void play_turn(game_data& gameinfo, game_state& state_of_game,
prefix = "#"; prefix = "#";
} }
const int resist=int(100.0-ceil(100.0*resistance)); const int resist = 100 - int(round(100.0*resistance));
const std::string& lang_weapon =
string_table["weapon_type_" + i->first];
const std::string& weap = lang_weapon.empty() ? i->first :
lang_weapon;
std::stringstream str; std::stringstream str;
str << i->first << "," << prefix << resist << "%"; str << weap << "," << prefix << resist << "%";
items.push_back(str.str()); items.push_back(str.str());
} }
@ -692,7 +711,7 @@ void play_turn(game_data& gameinfo, game_state& state_of_game,
gui.getImage(un->second.type().image_profile(),display::UNSCALED); gui.getImage(un->second.type().image_profile(),display::UNSCALED);
gui::show_dialog(gui,unit_image, gui::show_dialog(gui,unit_image,
un->second.type().language_name(), un->second.type().language_name(),
"Unit resistance table", string_table["unit_resistance_table"],
gui::MESSAGE,&items,&units_list); gui::MESSAGE,&items,&units_list);
} }
@ -719,7 +738,7 @@ void play_turn(game_data& gameinfo, game_state& state_of_game,
const double defense = move_type.defense_modifier(map,*t); const double defense = move_type.defense_modifier(map,*t);
const int def = int(100.0-ceil(100.0*defense)); const int def = 100-int(round(100.0*defense));
std::stringstream str; std::stringstream str;
str << lang_name << ","; str << lang_name << ",";

View File

@ -414,6 +414,8 @@ bool do_replay(display& disp, const gamemap& map, const game_data& gameinfo,
} }
game_events::fire("moveto",dst); game_events::fire("moveto",dst);
clear_shroud(disp,map,gameinfo,units,teams,team_num-1);
} }
else if((it = cfg->children.find("attack")) != cfg->children.end()) { else if((it = cfg->children.find("attack")) != cfg->children.end()) {

View File

@ -89,6 +89,8 @@ team::team_info::team_info(config& cfg)
tgt != tgts.end(); ++tgt) { tgt != tgts.end(); ++tgt) {
targets.push_back(target(**tgt)); targets.push_back(target(**tgt));
} }
use_shroud = (cfg.values["shroud"] == "yes");
} }
team::team(config& cfg, int gold) : gold_(gold), info_(cfg) team::team(config& cfg, int gold) : gold_(gold), info_(cfg)
@ -191,3 +193,36 @@ std::vector<team::target>& team::targets()
{ {
return info_.targets; return info_.targets;
} }
bool team::uses_shroud() const
{
return info_.use_shroud;
}
bool team::shrouded(size_t x, size_t y) const
{
if(info_.use_shroud == false)
return false;
if(x >= shroud_.size())
return true;
if(y >= shroud_[x].size())
return true;
return !shroud_[x][y];
}
void team::clear_shroud(size_t x, size_t y)
{
if(info_.use_shroud == false)
return;
if(x >= shroud_.size())
shroud_.resize(x+1);
if(y >= shroud_[x].size())
shroud_[x].resize(y+1);
shroud_[x][y] = true;
}

View File

@ -46,6 +46,8 @@ public:
double leader_value, village_value; double leader_value, village_value;
std::vector<target> targets; std::vector<target> targets;
bool use_shroud;
}; };
team(config& cfg, int gold=100); team(config& cfg, int gold=100);
@ -74,10 +76,16 @@ public:
int villages_per_scout() const; int villages_per_scout() const;
std::vector<target>& targets(); std::vector<target>& targets();
bool uses_shroud() const;
bool shrouded(size_t x, size_t y) const;
void clear_shroud(size_t x, size_t y);
private: private:
int gold_; int gold_;
std::set<gamemap::location> towers_; std::set<gamemap::location> towers_;
std::vector<std::vector<bool> > shroud_;
team_info info_; team_info info_;
}; };

View File

@ -45,7 +45,7 @@ bool compare_unit_values::operator()(const unit& a, const unit& b) const
unit::unit(game_data& data, config& cfg) : state_(STATE_NORMAL), unit::unit(game_data& data, config& cfg) : state_(STATE_NORMAL),
moves_(0), facingLeft_(true), moves_(0), facingLeft_(true),
recruit_(false), recruit_(false),
guardian_(false) guardian_(false), loyal_(false)
{ {
read(data,cfg); read(data,cfg);
} }
@ -63,7 +63,7 @@ unit::unit(const unit_type* t, int side, bool use_traits) :
backupMaxMovement_(t->movement()), backupMaxMovement_(t->movement()),
recruit_(false), attacks_(t->attacks()), recruit_(false), attacks_(t->attacks()),
backupAttacks_(t->attacks()), backupAttacks_(t->attacks()),
guardian_(false) guardian_(false), loyal_(false)
{ {
//calculate the unit's traits //calculate the unit's traits
std::vector<config*> traits = t->possible_traits(); std::vector<config*> traits = t->possible_traits();
@ -113,7 +113,7 @@ unit::unit(const unit_type* t, const unit& u) :
attacks_(t->attacks()), backupAttacks_(t->attacks()), attacks_(t->attacks()), backupAttacks_(t->attacks()),
modifications_(u.modifications_), modifications_(u.modifications_),
traitsDescription_(u.traitsDescription_), traitsDescription_(u.traitsDescription_),
guardian_(false) guardian_(false), loyal_(false)
{ {
//apply modifications etc, refresh the unit //apply modifications etc, refresh the unit
new_level(); new_level();
@ -491,7 +491,7 @@ const std::string& unit::image() const
attackType_->get_frame(attackingMilliseconds_); attackType_->get_frame(attackingMilliseconds_);
if(img == NULL) if(img == NULL)
return type_->image(); return type_->image_fighting(attackType_->range());
else else
return *img; return *img;
} }
@ -639,6 +639,8 @@ void unit::add_modification(const std::string& type, config& mod, bool no_add)
if(maxExperience_ < 1) { if(maxExperience_ < 1) {
maxExperience_ = 1; maxExperience_ = 1;
} }
} else if(apply_to == "loyal") {
loyal_ = true;
} }
} }
} }
@ -654,3 +656,27 @@ void unit::apply_modifications()
} }
} }
} }
int unit::upkeep() const
{
//special units with descriptions don't have any upkeep,
//as they are major units, not hired units
if(description_.empty() == false)
return 0;
//loyal units always have an upkeep of 1 gold. Other units have an
//upkeep equal to their level
return loyal_ ? 1 : type().level();
}
int team_upkeep(const unit_map& units, int side)
{
int res = 0;
for(unit_map::const_iterator i = units.begin(); i != units.end(); ++i) {
if(i->second.side() == side) {
res += i->second.upkeep();
}
}
return res;
}

View File

@ -95,6 +95,8 @@ public:
const gamemap::location& get_goto() const; const gamemap::location& get_goto() const;
void set_goto(const gamemap::location& new_goto); void set_goto(const gamemap::location& new_goto);
int upkeep() const;
void add_modification(const std::string& type, config& modification, void add_modification(const std::string& type, config& modification,
bool no_add=false); bool no_add=false);
@ -138,6 +140,8 @@ private:
gamemap::location goto_; gamemap::location goto_;
bool loyal_;
void apply_modifications(); void apply_modifications();
}; };
@ -148,4 +152,6 @@ struct compare_unit_values
typedef std::map<gamemap::location,unit> unit_map; typedef std::map<gamemap::location,unit> unit_map;
int team_upkeep(const unit_map& units, int team_num);
#endif #endif

View File

@ -396,6 +396,21 @@ const std::string& unit_type::image() const
return cfg_.values["image"]; return cfg_.values["image"];
} }
const std::string& unit_type::image_fighting(attack_type::RANGE range) const
{
static const std::string short_range("image_short");
static const std::string long_range("image_long");
const std::string& str = range == attack_type::LONG_RANGE ?
long_range : short_range;
const std::string& val = cfg_.values[str];
if(!val.empty())
return val;
else
return image();
}
const std::string& unit_type::image_defensive(attack_type::RANGE range) const const std::string& unit_type::image_defensive(attack_type::RANGE range) const
{ {
{ {

View File

@ -129,6 +129,7 @@ public:
const std::string& name() const; const std::string& name() const;
const std::string& image() const; const std::string& image() const;
const std::string& image_profile() const; const std::string& image_profile() const;
const std::string& image_fighting(attack_type::RANGE range) const;
const std::string& image_defensive(attack_type::RANGE range) const; const std::string& image_defensive(attack_type::RANGE range) const;
const std::string& unit_description() const; const std::string& unit_description() const;
int hitpoints() const; int hitpoints() const;

View File

@ -76,7 +76,7 @@ namespace {
} }
} }
CVideo::CVideo(const char* text) : frameBuffer(NULL) CVideo::CVideo() : frameBuffer(NULL)
{ {
const int res = const int res =
SDL_Init( SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_NOPARACHUTE); SDL_Init( SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_NOPARACHUTE);
@ -85,13 +85,9 @@ CVideo::CVideo(const char* text) : frameBuffer(NULL)
std::cerr << "Could not initialize SDL: " << SDL_GetError() << "\n"; std::cerr << "Could not initialize SDL: " << SDL_GetError() << "\n";
throw CVideo::error(); throw CVideo::error();
} }
for(int i = 0; i != sizeof(text_); ++i) {
text_[i] = text[i];
}
} }
CVideo::CVideo( int x, int y, int bits_per_pixel, int flags, const char* text ) CVideo::CVideo( int x, int y, int bits_per_pixel, int flags)
: frameBuffer(NULL) : frameBuffer(NULL)
{ {
const int res = SDL_Init( SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_NOPARACHUTE); const int res = SDL_Init( SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_NOPARACHUTE);
@ -100,10 +96,6 @@ CVideo::CVideo( int x, int y, int bits_per_pixel, int flags, const char* text )
} }
setMode( x, y, bits_per_pixel, flags ); setMode( x, y, bits_per_pixel, flags );
for(int i = 0; i != sizeof(text_); ++i) {
text_[i] = text[i];
}
} }
CVideo::~CVideo() CVideo::~CVideo()

View File

@ -22,8 +22,8 @@
class CVideo { class CVideo {
public: public:
CVideo(const char* text); CVideo();
CVideo( int x, int y, int bits_per_pixel, int flags, const char* text ); CVideo(int x, int y, int bits_per_pixel, int flags);
~CVideo(); ~CVideo();
int modePossible( int x, int y, int bits_per_pixel, int flags ); int modePossible( int x, int y, int bits_per_pixel, int flags );
@ -56,7 +56,6 @@ class CVideo {
private: private:
SDL_Surface* frameBuffer; SDL_Surface* frameBuffer;
char text_[256*8];
}; };
void allow_resizing(bool); void allow_resizing(bool);