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}
[trait]
name=loyal
[effect]
apply_to=loyal
[/effect]
[/trait]
[trait]
name=strong
[effect]
@ -38,7 +45,7 @@
name=intelligent
[effect]
apply_to=max_experience
increase=-7
increase=-6
[/effect]
[/trait]
@ -64,6 +71,8 @@
mountains=3
village=1
castle=1
cave=2
cavewall=100
[/movement costs]
[defense]
@ -76,6 +85,8 @@
mountains=0.4
village=0.4
castle=0.4
cave=0.6
cavewall=0.1
[/defense]
[resistance]
@ -100,6 +111,8 @@
mountains=2
village=1
castle=1
cave=1
cavewall=100
[/movement costs]
[defense]
@ -112,6 +125,7 @@
mountains=0.4
village=0.6
castle=0.6
cave=0.6
[/defense]
[resistance]
@ -136,6 +150,8 @@
mountains=3
village=1
castle=1
cave=1
cavewall=100
[/movement costs]
[defense]
@ -148,6 +164,7 @@
mountains=0.3
village=0.3
castle=0.3
cave=0.5
[/defense]
[resistance]
@ -173,6 +190,8 @@
mountains=100
village=1
castle=1
cave=4
cavewall=100
[/movement costs]
[defense]
@ -185,6 +204,7 @@
mountains=0.8
village=0.6
castle=0.6
cave=0.8
[/defense]
[resistance]
@ -209,6 +229,8 @@
mountains=4
village=1
castle=1
cave=3
cavewall=100
[/movement costs]
[defense]
@ -221,6 +243,7 @@
mountains=0.4
village=0.4
castle=0.4
cave=0.7
[/defense]
[resistance]
@ -245,6 +268,8 @@
mountains=1
village=1
castle=1
cave=2
cavewall=100
[/movement costs]
[defense]
@ -257,6 +282,7 @@
mountains=0.7
village=0.7
castle=0.7
cave=0.7
[/defense]
[resistance]
@ -281,6 +307,8 @@
mountains=100
village=1
castle=1
cave=3
cavewall=100
[/movement costs]
[defense]
@ -293,6 +321,7 @@
mountains=0.8
village=0.6
castle=0.6
cave=0.8
[/defense]
[resistance]
@ -317,6 +346,8 @@
mountains=1
village=1
castle=1
cave=1
cavewall=100
[/movement costs]
[defense]
@ -329,6 +360,7 @@
mountains=0.3
village=0.6
castle=0.6
cave=0.5
[/defense]
[resistance]
@ -341,42 +373,6 @@
[/resistance]
[/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]
name=undeadfoot
[movement costs]
@ -389,6 +385,8 @@
mountains=100
village=1
castle=1
cave=2
cavewall=100
[/movement costs]
[defense]
@ -401,6 +399,7 @@
mountains=0.4
village=0.4
castle=0.4
cave=0.6
[/defense]
[resistance]
@ -425,6 +424,8 @@
mountains=1
village=1
castle=1
cave=1
cavewall=100
[/movement costs]
[defense]
@ -437,6 +438,7 @@
mountains=0.5
village=0.5
castle=0.5
cave=0.6
[/defense]
[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]
type=Orcish Grunt
type=Orcish Crossbow
description=Urug-Telfar
side=2
canrecruit=1

View file

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

View file

@ -74,8 +74,8 @@ Defeat:
description=Knafa-Telfar
side=2
canrecruit=1
recruit=Orcish Warrior,Wolf Rider,Orcish Crossbow,Orcish Assasin,Troll
gold=250
recruit=Orcish Warrior,Wolf Rider,Orcish Crossbow,Orcish Assasin,Troll Warrior
gold=450
enemy=1
[/side]
@ -84,8 +84,8 @@ Defeat:
description=Urug-Tan
side=3
canrecruit=1
recruit=Orcish Grunt,Goblin Knight,Orcish Crossbow,Orcish Assasin,Troll
gold=300
recruit=Orcish Grunt,Goblin Knight,Orcish Crossbow,Orcish Assasin,Troll Warrior
gold=500
enemy=1
[/side]
@ -96,7 +96,7 @@ Defeat:
side=4
canrecruit=1
recruit=Orcish Warrior,Wolf Rider,Orcish Crossbow,Troll Warrior,Orcish Slayer
gold=300
gold=500
enemy=1
[/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
blue=100
[/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]
command=recall
key=c
ctrl=yes
key=r
alt=yes
[/hotkey]
[hotkey]
command=cycle
@ -73,6 +73,11 @@ language="English"
key=s
ctrl=yes
[/hotkey]
[hotkey]
command=endturn
key=e
alt=yes
[/hotkey]
game_title="The Battle for Wesnoth"
version="Version"
@ -143,12 +148,13 @@ early_finish_bonus="Early finish bonus"
per_turn="per turn"
turns_finished_early="Turns finished early"
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"
gold="Gold"
turn="Turn"
villages="Villages"
units="Units"
upkeep="Upkeep"
income="Income"
name="Name"
@ -221,6 +227,7 @@ movement="Movement"
defense="Defense"
attack_resistance="Resistance"
unit_resistance_table="Unit resistance table"
close_window="Close Window"
see_also="See Also..."
@ -242,5 +249,7 @@ forest="Forest"
bridge="Bridge"
castle="Castle"
keep="Keep"
cave="Cave"
cavewall="Cave Wall"
[/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
alignment=lawful
advanceto=Elvish Ranger,Elvish Marksman
cost=22
cost=18
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."
[attack]

View file

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

View file

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

View file

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

View file

@ -9,7 +9,7 @@ experience=32
level=1
alignment=neutral
advanceto=Elvish Druid
cost=27
cost=21
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."

View file

@ -8,7 +8,7 @@ experience=38
level=1
alignment=neutral
advanceto=Knight,Elvish Outrider
cost=28
cost=23
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."
[attack]

View file

@ -8,7 +8,7 @@ experience=45
level=1
alignment=neutral
advanceto=White Mage,Red Mage
cost=42
cost=34
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.

View file

@ -3,7 +3,7 @@ name=Princess
image=human-princess.png
hitpoints=48
movement_type=elusivefoot
movement=7
movement=6
experience=500
level=3
alignment=neutral
@ -11,7 +11,7 @@ advanceto=null
cost=110
ability=leadership
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]
name=sword
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::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;
@ -75,7 +75,8 @@ std::string recruit_unit(const gamemap& map, int side,
}
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)) {
@ -87,7 +88,8 @@ std::string recruit_unit(const gamemap& map, int side,
units.insert(std::pair<gamemap::location,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);
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,
a->second.attacks()[attack_with]);
if(dies) {
attackerxp = 10*d->second.type().level();
attackerxp = 8*d->second.type().level();
if(d->second.type().level() == 0)
attackerxp = 5;
attackerxp = 4;
defenderxp = 0;
@ -386,9 +388,9 @@ void attack(display& gui, const gamemap& map,
d->second.attacks()[stats.defend_with]);
if(dies) {
defenderxp = 10*a->second.type().level();
defenderxp = 8*a->second.type().level();
if(a->second.type().level() == 0)
defenderxp = 5;
defenderxp = 4;
attackerxp = 0;
@ -583,7 +585,8 @@ void calculate_healing(display& disp, const gamemap& map,
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);
@ -871,3 +874,53 @@ size_t move_unit(display* disp, const gamemap& map,
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::map<gamemap::location,unit>& units,
unit& unit, gamemap::location preferred_location,
display *disp=NULL);
display *disp=NULL, bool need_castle=true);
struct battle_stats
{
@ -112,4 +112,7 @@ size_t move_unit(display* disp, const gamemap& map,
const std::vector<gamemap::location>& steps,
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

View file

@ -103,7 +103,9 @@ void move_unit(const game_data& gameinfo, display& disp,
paths current_paths = paths(map,gameinfo,units,from,teams,
ignore_zocs,teleport);
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);
@ -402,6 +404,9 @@ void do_move(display& disp, const gamemap& map, const game_data& gameinfo,
}
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);
if(un == units.end()) {
assert(false);
@ -419,7 +424,6 @@ void do_move(display& disp, const gamemap& map, const game_data& gameinfo,
return;
}
}
std::cout << "b\n";
//find units in need of healing
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
//find a vacant village for it to rest in
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()) {
typedef std::multimap<location,location>::iterator Itor;
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()) {
const location& src = it.first->first;
std::cerr << "moving unit to village for healing...\n";
move_unit(gameinfo,disp,map,units,src,dst,
possible_moves,teams,team_num);
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
for(++u; u != units.end(); ++u) {
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;
}

View file

@ -52,7 +52,7 @@ struct config
const std::vector<line_source>* lines=0); //throws config::error
std::string write() const;
std::map<std::string,std::string> values;
string_map values;
std::map<std::string,std::vector<config*> > children;
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)
{
if(team_valid() && teams_[currentTeam_].shrouded(hex.x,hex.y)) {
return;
}
invalidate(selectedHex_);
selectedHex_ = hex;
invalidate(selectedHex_);
@ -203,13 +207,22 @@ void display::zoom(double amount)
clear_surfaces(brightenedImages_);
energy_bar_count_ = std::pair<int,int>(-1,-1);
const double orig_xpos = xpos_;
const double orig_ypos = ypos_;
xpos_ /= zoom_;
ypos_ /= zoom_;
const double max_zoom = 200.0;
const double orig_zoom = zoom_;
zoom_ += amount;
if(zoom_ > max_zoom)
zoom_ = max_zoom;
if(zoom_ > max_zoom) {
zoom_ = orig_zoom;
xpos_ = orig_xpos;
ypos_ = orig_ypos;
return;
}
xpos_ *= zoom_;
ypos_ *= zoom_;
@ -217,8 +230,17 @@ void display::zoom(double amount)
xpos_ += amount*2;
ypos_ += amount*2;
const double prev_zoom = zoom_;
bounds_check_position();
if(zoom_ != prev_zoom) {
xpos_ = orig_xpos;
ypos_ = orig_ypos;
zoom_ = orig_zoom;
return;
}
invalidate_all();
}
@ -229,7 +251,7 @@ void display::default_zoom()
void display::scroll_to_tile(int x, int y, SCROLL_TYPE scroll_type)
{
if(update_locked())
if(update_locked() || shrouded(x,y))
return;
const double xpos = static_cast<double>(x)*zoom_*0.75 - xpos_;
@ -440,7 +462,7 @@ void display::draw_sidebar()
i = units_.find(selectedHex_);
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_);
invalidateUnit_ = false;
}
@ -494,21 +516,29 @@ void display::draw_game_status(int x, int y)
int nunits = 0;
for(std::map<gamemap::location,unit>::const_iterator uit = units_.begin();
uit != units_.end(); ++uit) {
if(uit->second.side() == currentTeam_+1) {
if(size_t(uit->second.side()) == currentTeam_+1) {
++nunits;
}
}
const int income = teams_[currentTeam_].income() - nunits;
std::stringstream details;
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["income"] << ": " << income << "\n";
if(team_valid()) {
const int upkeep = team_upkeep(units_,currentTeam_+1);
const int expenses = upkeep - teams_[currentTeam_].towers().size();
const int income = teams_[currentTeam_].income() - maximum(expenses,0);
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_)) {
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_ypos = (int)get_location_y(se_loc);
const bool is_shrouded = shrouded(x,y);
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];
}
IMAGE_TYPE image_type = SCALED;
@ -887,14 +919,23 @@ void display::draw_tile(int x, int y, SDL_Surface* unit_image,
return;
}
std::vector<SDL_Surface*> overlaps = getAdjacentTerrain(x,y,image_type);
typedef std::multimap<gamemap::location,std::string>::const_iterator Itor;
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);
std::vector<SDL_Surface*> overlaps;
if(!is_shrouded) {
overlaps = getAdjacentTerrain(x,y,image_type);
typedef std::multimap<gamemap::location,std::string>::const_iterator
Itor;
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;
if(it->second.side() != currentTeam_+1) {
if(teams_[currentTeam_].is_enemy(it->second.side())) {
if(size_t(it->second.side()) != currentTeam_+1) {
if(team_valid() &&
teams_[currentTeam_].is_enemy(it->second.side())) {
energy_file = "enemy-energy.png";
} else {
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);
}
if(unit_image == NULL || energy_image == NULL)
if(unit_image == NULL || energy_image == NULL || is_shrouded)
return;
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 x = 0; x != map_.x(); ++x) {
*data = map_.get_terrain_info(map_[x][y]).get_rgb().
format(surface->format);
if(shrouded(x,y))
*data = 0;
else
*data = map_.get_terrain_info(map_[x][y]).get_rgb().
format(surface->format);
++data;
}
@ -1600,6 +1645,9 @@ bool display::unit_attack_ranged(const gamemap::location& a,
const gamemap::location& b, int damage,
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);
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
//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;
if(sfx.empty() == false) {
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;
}
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) ?
NULL : getImage(*unit_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);
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 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();
if(wait_time > 0 && !turbo() && !update_locked())
if(wait_time > 0 && !turbo() && !hide)
SDL_Delay(wait_time);
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)
{
if(update_locked())
if(update_locked() || shrouded(loc.x,loc.y))
return;
const int frame_time = 30;
@ -1764,6 +1817,8 @@ bool display::unit_attack(const gamemap::location& a,
const gamemap::location& b, int damage,
const attack_type& attack)
{
const bool hide = update_locked() || shrouded(a.x,a.y) && shrouded(b.x,b.y);
log_scope("unit_attack");
invalidate_all();
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
//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;
if(sfx.empty() == false) {
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 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());
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);
ticks = SDL_GetTicks();
@ -1900,7 +1955,9 @@ void display::move_unit_between(const gamemap::location& a,
const gamemap::location& b,
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;
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);
const Pixel ShroudColour = 0;
for(; y != endy; ++y, src += src_increment) {
Pixel* dst = screen_lock.pixels() + y*screen->w + x;
if(alpha == 1.0) {
if(reverse) {
for(int i = xoffset; i != len; ++i) {
if(dst[i-xoffset] == ShroudColour)
continue;
if(src[i] == semi_trans)
dst[i-xoffset] = alpha_blend_pixels(
0,dst[i-xoffset],fmt,0.5);
@ -2074,6 +2136,9 @@ void display::draw_unit(int x, int y, SDL_Surface* image,
}
} else {
for(int i = image->w-1-xoffset; i != image->w-len-1; --i,++dst){
if(*dst == ShroudColour)
continue;
if(src[i] == semi_trans)
*dst = alpha_blend_pixels(0,*dst,fmt,0.5);
else if(src[i] != 0)
@ -2083,6 +2148,9 @@ void display::draw_unit(int x, int y, SDL_Surface* image,
} else {
if(reverse) {
for(int i = xoffset; i != len; ++i) {
if(dst[i-xoffset] == ShroudColour)
continue;
const Pixel blend = blendto ? blendto : dst[i-xoffset];
if(src[i] != 0)
@ -2091,6 +2159,9 @@ void display::draw_unit(int x, int y, SDL_Surface* image,
}
} else {
for(int i = image->w-1-xoffset; i != image->w-len-1; --i,++dst){
if(*dst == ShroudColour)
continue;
const Pixel blend = blendto ? blendto : *dst;
if(src[i] != 0)
*dst = alpha_blend_pixels(src[i],blend,fmt,alpha);
@ -2172,8 +2243,9 @@ void display::remove_overlay(const gamemap::location& loc)
overlays_.erase(loc);
}
void display::set_team(int team)
void display::set_team(size_t team)
{
assert(team < teams_.size());
currentTeam_ = team;
}
@ -2226,3 +2298,16 @@ void display::clear_debug_highlights()
{
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);
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);
@ -117,6 +117,8 @@ public:
static void debug_highlight(const gamemap::location& loc, double amount);
static void clear_debug_highlights();
bool shrouded(int x, int y) const;
private:
display(const display&);
void operator=(const display&);
@ -182,6 +184,8 @@ private:
const gamestatus& status_;
bool team_valid() const;
const std::vector<team>& teams_;
int lastDraw_;
@ -200,7 +204,7 @@ private:
bool sideBarBgDrawn_;
int lastTimeOfDay_;
int currentTeam_;
size_t currentTeam_;
//used to store a unit that is not drawn, because it's currently
//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;
}
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) {
std::cerr << "Could not render ttf: '" << text << "'\n";
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_FreeSurface(surface);
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)
{
std::string text_chr = read_file("data/text.chr");
text_chr.resize(256*8);
CVideo video(text_chr.c_str());
CVideo video;
const font::manager font_manager;
const sound::manager sound_manager;
const preferences::manager prefs_manager;

View file

@ -16,12 +16,12 @@ namespace game_config
{
const int unit_cost = 1;
const int base_income = 2;
const int tower_income = 2;
const int tower_income = 1;
const int heal_amount = 4;
const int healer_heals_per_turn = 8;
const int cure_amount = 8;
const int curer_heals_per_turn = 18;
const int recall_cost = 20;
const std::string version = "0.4.8";
const std::string version = "0.4.9-CVS";
bool debug = false;
}

View file

@ -15,6 +15,7 @@
#include "language.hpp"
#include "playlevel.hpp"
#include "replay.hpp"
#include "sound.hpp"
#include <cstdlib>
#include <deque>
@ -55,8 +56,8 @@ bool conditional_passed(game_state& state_of_game,
std::vector<config*>& variables = cond.children["variable"];
for(std::vector<config*>::iterator var = variables.begin();
var != variables.end(); ++var) {
std::map<std::string,std::string>& values = (*var)->values;
std::map<std::string,std::string>& vars = state_of_game.variables;
string_map& values = (*var)->values;
string_map& vars = state_of_game.variables;
const std::string& name = values["name"];
//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 double num_value = atof(value.c_str());
std::map<std::string,std::string>::iterator itor;
string_map::iterator itor;
itor = values.find("equals");
if(itor != values.end() && itor->second != value) {
@ -127,6 +128,7 @@ namespace {
display* screen = NULL;
gamemap* game_map = NULL;
std::map<gamemap::location,unit>* units = NULL;
std::vector<team>* teams = NULL;
game_state* state_of_game = 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);
}
//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
std::vector<config*>& set_vars = cfg->children["set_variable"];
for(std::vector<config*>::iterator var = set_vars.begin();
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& value = vals["value"];
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();
u != avail.end(); ++u) {
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);
if(u == avail.end())
break;
@ -352,7 +376,7 @@ void event_handler::handle_event(const queued_event& event_info, config* cfg)
std::vector<config*>& objects = cfg->children["object"];
for(std::vector<config*>::iterator obj = objects.begin();
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(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"];
for(std::vector<config*>::iterator msg = messages.begin();
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();
if(values["speaker"] == "unit") {
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"];
std::string image = (*msg)->values["image"];
@ -665,6 +695,7 @@ namespace game_events {
manager::manager(config& cfg, display& gui_, gamemap& map_,
std::map<gamemap::location,unit>& units_,
std::vector<team>& teams_,
game_state& state_of_game_, game_data& game_data_)
{
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));
}
teams = &teams_;
screen = &gui_;
game_map = &map_;
units = &units_;

View file

@ -17,6 +17,7 @@
#include "display.hpp"
#include "gamestatus.hpp"
#include "map.hpp"
#include "team.hpp"
#include "unit.hpp"
#include "unit_types.hpp"
@ -31,7 +32,7 @@ bool conditional_passed(game_state& state_of_game,
struct manager {
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);
~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("recruit",HOTKEY_RECRUIT));
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);

View file

@ -23,7 +23,7 @@ enum HOTKEY_COMMAND { HOTKEY_CYCLE_UNITS, HOTKEY_END_UNIT_TURN, HOTKEY_LEADER,
HOTKEY_FULLSCREEN, HOTKEY_ACCELERATED,
HOTKEY_TERRAIN_TABLE, HOTKEY_ATTACK_RESISTANCE,
HOTKEY_UNIT_DESCRIPTION, HOTKEY_SAVE_GAME,
HOTKEY_RECRUIT, HOTKEY_RECALL,
HOTKEY_RECRUIT, HOTKEY_RECALL, HOTKEY_ENDTURN,
HOTKEY_NULL };
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 so_far) const
{
if(!map_.on_board(loc))
if(!map_.on_board(loc) || team_.shrouded(loc.x,loc.y))
return 100000.0;
const unit_map::const_iterator enemy_unit = units_.find(loc);

View file

@ -51,7 +51,8 @@ struct paths
int move_left;
};
std::map<gamemap::location,route> routes;
typedef std::map<gamemap::location,route> routes_map;
routes_map routes;
};
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"]));
CKey key;
typedef std::map<gamemap::location,unit> units_map;
units_map units;
unit_map units;
std::vector<team> teams;
@ -99,7 +98,7 @@ LEVEL_RESULT play_level(game_data& gameinfo, config& terrain_config,
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);
//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"]);
}
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();
}
@ -124,6 +123,8 @@ LEVEL_RESULT play_level(game_data& gameinfo, config& terrain_config,
try {
if(first_time) {
clear_shroud(gui,map,gameinfo,units,teams,0);
update_locker lock_display(gui,recorder.skipping());
game_events::fire("start");
gui.draw();
@ -135,10 +136,12 @@ LEVEL_RESULT play_level(game_data& gameinfo, config& terrain_config,
team_it != teams.end(); ++team_it) {
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);
//scroll the map to the leader
const units_map::iterator leader =
const unit_map::iterator leader =
find_leader(units,player_number);
if(leader != units.end() && !recorder.skipping()) {
@ -175,7 +178,7 @@ LEVEL_RESULT play_level(game_data& gameinfo, config& terrain_config,
SDL_Delay(1000);
}
for(units_map::iterator uit = units.begin();
for(unit_map::iterator uit = units.begin();
uit != units.end(); ++uit) {
if(uit->second.side() == player_number)
uit->second.end_turn();
@ -206,18 +209,25 @@ LEVEL_RESULT play_level(game_data& gameinfo, config& terrain_config,
}
std::map<int,int> expenditure;
for(units_map::iterator i = units.begin();
for(unit_map::iterator i = units.begin();
i != units.end(); ++i) {
i->second.new_turn();
expenditure[i->second.side()]++;
}
int team_num = 1;
for(std::vector<team>::iterator it = teams.begin();
it != teams.end(); ++it, ++team_num) {
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) {
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 finishing_bonus = end_level.gold_bonus ?
(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"],
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);
//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
std::map<gamemap::location,paths::route>::const_iterator
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
<< ") " << stats.damage_defender_takes << "-"
<< 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 << defend_name << " (" << defend_type
<< ") " << stats.damage_attacker_takes << "-"
<< 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());
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,
current_route.steps,&recorder,&undo_stack);
redo_stack.clear();
selected_hex = gamemap::location();
@ -341,6 +348,9 @@ void play_turn(game_data& gameinfo, game_state& state_of_game,
gui.set_paths(&current_paths);
}
if(clear_shroud(gui,map,gameinfo,units,teams,team_num-1)) {
undo_stack.clear();
}
} else {
gui.set_paths(NULL);
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"]) {
recorder.save_game(gameinfo,string_table["auto_save"]);
recorder.end_turn();
return;
command = HOTKEY_ENDTURN;
}
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)
command = check_keys(gui);
if(command == HOTKEY_ENDTURN) {
recorder.save_game(gameinfo,string_table["auto_save"]);
recorder.end_turn();
return;
}
if(command == HOTKEY_RECRUIT) {
std::vector<unit> sample_units;
@ -679,10 +693,15 @@ void play_turn(game_data& gameinfo, game_state& state_of_game,
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;
str << i->first << "," << prefix << resist << "%";
str << weap << "," << prefix << resist << "%";
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::show_dialog(gui,unit_image,
un->second.type().language_name(),
"Unit resistance table",
string_table["unit_resistance_table"],
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 int def = int(100.0-ceil(100.0*defense));
const int def = 100-int(round(100.0*defense));
std::stringstream str;
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);
clear_shroud(disp,map,gameinfo,units,teams,team_num-1);
}
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) {
targets.push_back(target(**tgt));
}
use_shroud = (cfg.values["shroud"] == "yes");
}
team::team(config& cfg, int gold) : gold_(gold), info_(cfg)
@ -191,3 +193,36 @@ std::vector<team::target>& team::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;
std::vector<target> targets;
bool use_shroud;
};
team(config& cfg, int gold=100);
@ -74,10 +76,16 @@ public:
int villages_per_scout() const;
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:
int gold_;
std::set<gamemap::location> towers_;
std::vector<std::vector<bool> > shroud_;
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),
moves_(0), facingLeft_(true),
recruit_(false),
guardian_(false)
guardian_(false), loyal_(false)
{
read(data,cfg);
}
@ -63,7 +63,7 @@ unit::unit(const unit_type* t, int side, bool use_traits) :
backupMaxMovement_(t->movement()),
recruit_(false), attacks_(t->attacks()),
backupAttacks_(t->attacks()),
guardian_(false)
guardian_(false), loyal_(false)
{
//calculate the unit's 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()),
modifications_(u.modifications_),
traitsDescription_(u.traitsDescription_),
guardian_(false)
guardian_(false), loyal_(false)
{
//apply modifications etc, refresh the unit
new_level();
@ -491,7 +491,7 @@ const std::string& unit::image() const
attackType_->get_frame(attackingMilliseconds_);
if(img == NULL)
return type_->image();
return type_->image_fighting(attackType_->range());
else
return *img;
}
@ -639,6 +639,8 @@ void unit::add_modification(const std::string& type, config& mod, bool no_add)
if(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;
void set_goto(const gamemap::location& new_goto);
int upkeep() const;
void add_modification(const std::string& type, config& modification,
bool no_add=false);
@ -138,6 +140,8 @@ private:
gamemap::location goto_;
bool loyal_;
void apply_modifications();
};
@ -148,4 +152,6 @@ struct compare_unit_values
typedef std::map<gamemap::location,unit> unit_map;
int team_upkeep(const unit_map& units, int team_num);
#endif

View file

@ -396,6 +396,21 @@ const std::string& unit_type::image() const
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
{
{

View file

@ -129,6 +129,7 @@ public:
const std::string& name() const;
const std::string& image() 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& unit_description() 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 =
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";
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)
{
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 );
for(int i = 0; i != sizeof(text_); ++i) {
text_[i] = text[i];
}
}
CVideo::~CVideo()

View file

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