merged syncpoint_gettext1_1 from trunk

This commit is contained in:
Yann Dirson 2004-06-25 23:04:51 +00:00
parent dc3202ddc5
commit 4c9a6d303f
81 changed files with 1551 additions and 461 deletions

View file

@ -1,3 +1,21 @@
CVS HEAD:
* multiplayer improvements:
* new map: Battle for Weslin Bridge
* new map: Forest of Fear
* clipboard support for X11
* new rightside panel
* improved lite buttons
* improved clipboard functions
* various help browser improvements
* made The Eastern Invasion campaign translatable
* added icons for preferences and multiplayer dialogs
* fixed crash when loading an empty map
* fixed transition problems with forests
* fixed missing multiplayer map: Castles
* fixed wesnothd crashes
* fixed clashing msg ids
* code refactoring
Version 0.7.10:
* help browser, hotkey is <F1>
* new tabbed preferences dialog

View file

@ -332,6 +332,10 @@ What would you like to wish for?"
y={Y}
[/filter]
[object]
[filter]
x={X}
y={Y}
[/filter]
id={ID}
name=Healing
image=misc/item-healingpotion.png
@ -361,6 +365,10 @@ What would you like to wish for?"
y={Y}
[/filter]
[object]
[filter]
x={X}
y={Y}
[/filter]
id={ID}
name=Poison
image=item-potion2.png
@ -390,6 +398,10 @@ What would you like to wish for?"
y={Y}
[/filter]
[object]
[filter]
x={X}
y={Y}
[/filter]
id={ID}
name=Holy Water
image=misc/item-holywater.png
@ -420,6 +432,10 @@ What would you like to wish for?"
y={Y}
[/filter]
[object]
[filter]
x={X}
y={Y}
[/filter]
id={ID}
name=Strong
image=item-potion3.png
@ -455,6 +471,10 @@ What would you like to wish for?"
y={Y}
[/filter]
[object]
[filter]
x={X}
y={Y}
[/filter]
id={ID}
name=Decay
image=item-potion4.png
@ -484,6 +504,10 @@ What would you like to wish for?"
y={Y}
[/filter]
[object]
[filter]
x={X}
y={Y}
[/filter]
id={ID}
name=Ring of Regeneration
image=item-ring1.png
@ -519,6 +543,10 @@ What would you like to wish for?"
y={Y}
[/filter]
[object]
[filter]
x={X}
y={Y}
[/filter]
id={ID}
name=Ring of Slowness
image=item-ring2.png
@ -548,6 +576,10 @@ What would you like to wish for?"
y={Y}
[/filter]
[object]
[filter]
x={X}
y={Y}
[/filter]
id={ID}
name=Staff of Swiftness
image=misc/item-staff.png
@ -585,6 +617,7 @@ What would you like to wish for?"
cannot_use_message="Only the mermen can use this item!"
[filter]
type=Merman,Merman Lord,Triton
x,y={X},{Y}
[/filter]
[effect]
apply_to=new_attack
@ -633,6 +666,7 @@ What would you like to wish for?"
cannot_use_message="Only the leader of an army can wield this sword!"
[filter]
description=Konrad
x,y={X},{Y}
[/filter]
[effect]
apply_to=new_attack
@ -668,6 +702,11 @@ What would you like to wish for?"
[/filter]
[object]
[filter]
type=Princess,Commander,Lord
x,y={X},{Y}
[/filter]
id={ID}
name=Sceptre of Fire
@ -680,12 +719,6 @@ What would you like to wish for?"
cannot_use_message="This is the Sceptre of Fire. Only a true successor to the throne can possibly dare to take this!"
[filter]
type=Princess,Commander,Lord
[/filter]
[effect]
apply_to=new_attack

View file

@ -42,7 +42,7 @@ id=era_default
music="wesnoth-4.ogg"
terrain_liked=fwc
[ai]
recruitment_pattern=fighter,fighter,scout
recruitment_pattern=fighter,fighter,fighter,archer,archer,scout
[/ai]
[/multiplayer_side]
@ -117,7 +117,7 @@ id=era_classic
music="elf-land.ogg"
terrain_liked=fwc
[ai]
recruitment_pattern=fighter,fighter,scout
recruitment_pattern=fighter,fighter,fighter,archer,archer,scout
[/ai]
[/multiplayer_side]
@ -192,7 +192,7 @@ id=era_heroes
music="wesnoth-4.ogg"
terrain_liked=fwc
[ai]
recruitment_pattern=fighter,fighter,scout
recruitment_pattern=fighter,fighter,fighter,archer,archer,scout
[/ai]
[/multiplayer_side]

View file

@ -373,22 +373,27 @@ role={R}
#some talking
[message]
description=King Dra-Nak
id=msg_cmpgn_ei_14_01
message="Why have you entered my lands?!?"
[/message]
[message]
description=Gweddry
id=msg_cmpgn_ei_14_02
message="We were traveling-"
[/message]
[message]
description=King Dra-Nak
id=msg_cmpgn_ei_14_03
message="Silence! Did I ask you?"
[/message]
[message]
description=Dacyn
id=msg_cmpgn_ei_14_04
message="Um..yes."
[/message]
[message]
description=King Dra-Nak
id=msg_cmpgn_ei_14_05
message="Shut up! Thats it! I'm putting you in the high-security cave!"
[/message]
@ -405,18 +410,22 @@ role={R}
#Gweddry talks to himself
[message]
description=Gweddry
id=msg_cmpgn_ei_14_06
message="Ugh..."
[/message]
[message]
description=Gweddry
id=msg_cmpgn_ei_14_07
message="Huh? Where am I?"
[/message]
[message]
description=Gweddry
id=msg_cmpgn_ei_14_08
message="It looks like I'm in some sort of prison..."
[/message]
[message]
description=Gweddry
id=msg_cmpgn_ei_14_09
message="I think I will have to escape, and rescue Dacyn and Owaec."
[/message]
[/event]
@ -442,10 +451,12 @@ find_vacant=yes
{TRUEUNSTORE 4-6 16-18 O}
[message]
description=Gweddry
id=msg_cmpgn_ei_14_10
message="So you are in this cell! Come on, we have to escape!"
[/message]
[message]
description=Owaec
id=msg_cmpgn_ei_14_11
message="Very well. I think the rest of the cells are further down this path."
[/message]
[/event]
@ -456,6 +467,7 @@ find_vacant=yes
{TRUEUNSTORE 6-8 12-14 R2}
[message]
description=Gweddry
id=msg_cmpgn_ei_14_12
message="So, they must have captured $R2.user_description in addition to Dacyn, Owaec and me. Well, $R2.type, follow me. We have to get out of this dungeon."
[/message]
[/event]
@ -466,6 +478,7 @@ find_vacant=yes
{TRUEUNSTORE 6-8 8-10 R1}
[message]
description=Gweddry
id=msg_cmpgn_ei_14_13
message=" It is nice to have a $R1.type among us! My guess is $R1.user_description will be able to shoot these devils without them doing anything about it, since most orcs are melee."
[/message]
[/event]
@ -476,18 +489,22 @@ find_vacant=yes
{TRUEUNSTORE 6-8 4-6 D}
[message]
description=Gweddry
id=msg_cmpgn_ei_14_14
message="Dacyn! Good, now we can try to escape. Do you know any way to get out?"
[/message]
[message]
description=Dacyn
id=msg_cmpgn_ei_14_15
message="No, but I think I can be of some help. I think I have found out where the key to the door is!"
[/message]
[message]
description=Gweddry
id=msg_cmpgn_ei_14_16
message="Really? Where?"
[/message]
[message]
description=Dacyn
id=msg_cmpgn_ei_14_17
message="The wall of the northern part of my cell, and right outside of it, is thinner than everywhere else. I think there isa hidden door there. Come, let us see!"
[/message]
[set_variable]
@ -530,6 +547,7 @@ find_vacant=yes
[then]
[message]
description=Gweddry
id=msg_cmpgn_ei_14_18
message="Here is the thin spot. Actually- wait a second- its not a thin spot at all! Its really a door!"
[/message]
[terrain]
@ -539,6 +557,7 @@ find_vacant=yes
{GUARD 3 3 (Troll Warrior)}
[message]
description=Owaec
id=msg_cmpgn_ei_14_19
message="Huh! A guard. Lets see how quickly we can kill it."
[/message]
[item]
@ -561,6 +580,7 @@ find_vacant=yes
[/filter]
[message]
speaker=unit
id=msg_cmpgn_ei_14_20
message="I have found the key! Lets get out of here!"
[/message]
[set_variable]
@ -586,6 +606,7 @@ find_vacant=yes
[then]
[message]
description=Gweddry
id=msg_cmpgn_ei_14_21
message="This is the right key! Lets open the door, quick!"
[/message]
[terrain]
@ -610,10 +631,12 @@ find_vacant=yes
[/filter]
[message]
speaker=unit
id=msg_cmpgn_ei_14_22
message=The high security prisoners are escaping!
[/message]
[message]
description=King Dra-Nak
id=msg_cmpgn_ei_14_23
message=Kill them.
[/message]
#these are prisoners even though the macro is called PRISON
@ -639,10 +662,12 @@ find_vacant=yes
#a prisoner says something
[message]
speaker=narrator
id=msg_cmpgn_ei_14_24
message="The guards are distracted! Now is the time to escape!"
[/message]
[message]
description=Gweddry
id=msg_cmpgn_ei_14_25
message="What the...? Who said that?"
[/message]
[/event]
@ -666,14 +691,17 @@ find_vacant=yes
{PRISON 32 19}
[message]
description=Valand
id=msg_cmpgn_ei_14_26
message="The guards are planning to execute us tomorrow! Please help us!"
[/message]
[message]
x,y=34,20
id=msg_cmpgn_ei_14_27
message="Hah! Tomorrow? You make a big mistake if you believe you will live that long."
[/message]
[message]
x,y=30,20
id=msg_cmpgn_ei_14_28
message="Right, boss, especially since they're invading, and we need to kill them now before they escape!"
[/message]
[/event]
@ -688,6 +716,7 @@ find_vacant=yes
[/filter]
[message]
speaker=unit
id=msg_cmpgn_ei_14_29
message="Argh! Oh well, at least my vast hordes will defeat you!"
[/message]
{GUARD 20 10 (Orcish Grunt)}
@ -712,6 +741,7 @@ find_vacant=yes
[/filter]
[message]
description=Gweddry
id=msg_cmpgn_ei_14_30
message="Good! We have escaped these accursed caves, and can reunite with our army!"
[/message]
[endlevel]
@ -725,6 +755,7 @@ find_vacant=yes
name=victory
[message]
description=Valand
id=msg_cmpgn_ei_14_31
message="Thank you for rescuing me! I will help you on your quest, whatever it is."
[/message]
[/event]

View file

@ -87,34 +87,42 @@ Defeat:
[/recall]
[message]
description=Gweddry
id=msg_cmpgn_ei_09_01
message="We have come to a great river. What should we do? Should we attempt to cross it?"
[/message]
[message]
description=Dacyn
id=msg_cmpgn_ei_09_02
message="We must cross this river. The undead are chasing us. Reinforcements for the undead will arrive soon. we must be across the river before that happens."
[/message]
[message]
description=Owaec
id=msg_cmpgn_ei_09_03
message="Across this river lies the Northland. If we can get there, we may be able to get some ogres to help us."
[/message]
[message]
description=Grug
id=msg_cmpgn_ei_09_04
message="Grug say we no help you! We finish must battle orc with!"
[/message]
[message]
description=Draka-Kura
id=msg_cmpgn_ei_09_05
message="And in Wesnothish that means?..."
[/message]
[message]
description=Grug
id=msg_cmpgn_ei_09_06
message="Orc foolish! Die you now!"
[/message]
[message]
description=Gweddry
id=msg_cmpgn_ei_09_07
message="I think the ogres are trying to kill the orcs."
[/message]
[message]
description=Dacyn
id=msg_cmpgn_ei_09_08
message="If we show ourselves as enemies of the orcs, they may help us. But I think we should cross the river before trying to convince these ogres to help."
[/message]
[/event]
@ -164,6 +172,7 @@ letter=C
[/unit]
[message]
description=Dacyn
id=msg_cmpgn_ei_09_09
message="The undead reinforcements have arrived! We must cross the river immediately!"
[/message]
[terrain]
@ -182,10 +191,12 @@ letter=C
[then]
[message]
description=Dacyn
id=msg_cmpgn_ei_09_10
message="Good! We have crossed. Now let's see if we can get the Ogres to join us. They have been convinced to work for the Crown in the past; maybe it can be done again."
[/message]
[message]
description=Grug
id=msg_cmpgn_ei_09_11
message="Grug say join you maybe he."
[/message]
[endlevel]
@ -196,6 +207,7 @@ letter=C
[else]
[message]
speaker=unit
id=msg_cmpgn_ei_09_12
message="Hurry up. We need to get across before these undead slaughter us!"
[/message]
[set_variable]

View file

@ -75,14 +75,17 @@ Defeat:
[/recall]
[message]
description=Volas
id=msg_cmpgn_ei_04_01
message="Greetings, travelers! Welcome to my realm."
[/message]
[message]
description=Gweddry
id=msg_cmpgn_ei_04_02
message="Hello. I am wondering if you can help he fight these undead beasts that attack us."
[/message]
[message]
description=Volas
id=msg_cmpgn_ei_04_03
message="Certainly. Although we will not leave our forests, we will help you reach the northern outpost, where the Lieutenant stationed there may aid you."
[/message]
@ -103,18 +106,22 @@ Defeat:
[message]
description=Gruga-Har
id=msg_cmpgn_ei_04_04
message="Intruders!"
[/message]
[message]
description=Volas
id=msg_cmpgn_ei_04_05
message="What? Those pesky orcs! They are the intruders, not us!"
[/message]
[message]
description=Dacyn
id=msg_cmpgn_ei_04_06
message="They are right in the Northern Path. We will have to fight them to move on."
[/message]
[message]
description=Gruga-Har
id=msg_cmpgn_ei_04_07
message="Bring forth the assassins, we may be able to poison them!"
[/message]
@ -138,11 +145,13 @@ Defeat:
[message]
description=Nafga
id=msg_cmpgn_ei_04_08
message="Your Warlordship, I am the only assassin left! Do you want me to go poison their leader?"
[/message]
[message]
description=Gruga-Har
id=msg_cmpgn_ei_04_09
message="Perfect! Go, into the forest!"
[/message]
@ -160,6 +169,7 @@ Defeat:
[message]
description=Gweddry
id=msg_cmpgn_ei_04_10
message="They have sent an assassin into the forest. We will have to be careful, and make sure he does not come out and attack us unexpectedly."
[/message]
[/event]
@ -176,6 +186,7 @@ Defeat:
[message]
description=Nafga
id=msg_cmpgn_ei_04_11
message="Hahaha! Nafga will kill the elves!"
[/message]
[/event]
@ -188,11 +199,13 @@ Defeat:
[message]
description=Nafga
id=msg_cmpgn_ei_04_12
message="No! This is the first time I have failed a mission, and it is my last!"
[/message]
[message]
description=Gruga-Har
id=msg_cmpgn_ei_04_13
message="My assassin is dead! the elves must pay, not for his death, but for stopping him in his mission!"
[/message]
[/event]

View file

@ -89,10 +89,12 @@ Defeat:
[/recall]
[message]
description=Gweddry
id=msg_cmpgn_ei_02_01
message="Where are we? I cannot see where we are going."
[/message]
[message]
description=Dacyn
id=msg_cmpgn_ei_02_02
message="I do not know. There are trolls in here, which may try to fight us."
[/message]
[/event]
@ -113,6 +115,7 @@ Defeat:
[/filter]
[message]
speaker=narrator
id=msg_cmpgn_ei_02_03
message=The sign says 'Dead End'
[/message]
[/event]
@ -125,14 +128,17 @@ Defeat:
[/filter]
[message]
speaker=unit
id=msg_cmpgn_ei_02_04
message="Who goes there?"
[/message]
[message]
description=Gweddry
id=msg_cmpgn_ei_02_05
message="We are travelers loyal to the king of Wesnoth. Will you help us escape these trolls?"
[/message]
[message]
speaker=unit
id=msg_cmpgn_ei_02_06
message="Yes, we will help you, for although we have no loyalty to Wesnoth, we believe that you are on a noble quest."
[/message]
[/event]
@ -188,6 +194,7 @@ Defeat:
[/filter]
[message]
speaker=unit
id=msg_cmpgn_ei_02_07
message="There is a great fortune in this chest of treasure! I can count two hundred pieces of gold!"
[/message]
[gold]
@ -229,10 +236,12 @@ Defeat:
#endif
[message]
description=Mal-Bakral
id=msg_cmpgn_ei_02_08
message="We have found you, human- Prepare to die!"
[/message]
[message]
description=Gweddry
id=msg_cmpgn_ei_02_09
message="They follow us. We must move quickly!"
[/message]
[/event]
@ -245,8 +254,8 @@ Defeat:
description=Gweddry
[/filter]
[message]
id=lmsg2_3
description=Gweddry
id=msg_cmpgn_ei_02_10
message="We have reached the end of the escape tunnel. I see daylight above us."
[/message]
[endlevel]

View file

@ -77,18 +77,22 @@ Defeat:
[/recall]
[message]
description=Dacyn
id=msg_cmpgn_ei_13_01
message="The trail stops soon. Look at this- mountains block our path."
[/message]
[message]
description=Owaec
id=msg_cmpgn_ei_13_02
message="None of our troops can go on this harsh terrain. We must turn back!"
[/message]
[message]
description=Dacyn
id=msg_cmpgn_ei_13_03
message="If I remember correctly, there is a lake coming up here, with a bridge across it. It is the only way to get across the mountains."
[/message]
[message]
description=Owaec
id=msg_cmpgn_ei_13_04
message="Then let us go. Onward!"
[/message]
[/event]
@ -102,6 +106,7 @@ Defeat:
[/filter]
[message]
speaker=unit
id=msg_cmpgn_ei_13_05
message="This bridge is kind of rickety..."
[/message]
[/event]
@ -115,6 +120,7 @@ Defeat:
[/filter]
[message]
speaker=unit
id=msg_cmpgn_ei_13_06
message="This bridge is going to collapse soon! Quick, across the river!"
[/message]
[set_variable]
@ -143,6 +149,7 @@ Defeat:
[/terrain]
[message]
description=Gweddry
id=msg_cmpgn_ei_13_07
message="Ah! The bridge collapsed!"
[/message]
[if]
@ -154,12 +161,14 @@ Defeat:
[then]
[message]
description=Dacyn
id=msg_cmpgn_ei_13_08
message="Everyone who is across the river, onward! Everyone else, try to go around the lake!"
[/message]
[/then]
[else]
[message]
description=Dacyn
id=msg_cmpgn_ei_13_09
message="What? Now there is no way across! We will have to go around the lake."
[/message]
[/else]
@ -190,6 +199,7 @@ y=$y1
[/filter]
[message]
description=Gweddry
id=msg_cmpgn_ei_13_10
message="Good! We have made it to the end if the road. We can now get out of these mountains."
[/message]
[endlevel]

View file

@ -108,21 +108,25 @@ Defeat:
name=start
[message]
description=Gweddry
id=msg_cmpgn_ei_07_01
message="We have came all the way to Mal-Ravanal's Capital!"
[/message]
[message]
description=Dacyn
id=msg_cmpgn_ei_07_02
message="Yes, but look! The undead forces are closing in behind us. We cannot kill Mal-Ravanal. We must turn back!"
[/message]
[message]
description=Gweddry
id=msg_cmpgn_ei_07_03
message="True. We must kill one of these necromancers that follows us to retreat. Still, I think we have done some good here: these enemies are delayed by our actions."
[/message]
[message]
description=Mal-Ravanal
id=msg_cmpgn_ei_07_04
message="These humans have dared to come this far into my land. Crush them!"
[/message]
[/event]
@ -139,6 +143,7 @@ Defeat:
[/filter]
[message]
description=Mal-Ravanal
id=msg_cmpgn_ei_07_05
message="You dare to attack ME?!? Go back to your master!"
[/message]
[teleport]
@ -215,22 +220,27 @@ Defeat:
[/unit]
[message]
description=Terraent
id=msg_cmpgn_ei_07_06
message="Thank you for destroying that skeleton warrior! Every time you kill one of the advanced skeletons, one of my ally knights is let free!"
[/message]
[message]
description=Gweddry
id=msg_cmpgn_ei_07_07
message="Why? Are you the undead's prisoners?"
[/message]
[message]
description=Terraent
id=msg_cmpgn_ei_07_08
message="Yes. My allies and I were questing when we were ambushed by undead. The guard is playing a sick game- whenever one of their warriors dies, one of us is let free, but whenever you lose a fighter, they kill one of us."
[/message]
[message]
description=Dacyn
id=msg_cmpgn_ei_07_09
message= "This sounds like a dangerous game. We will try to free as many of you as possible before we escape from here."
[/message]
[message]
description=Terraent
id=msg_cmpgn_ei_07_10
message="There are five of us still locked up in the jail. All of us will join you if you can get us free."
[/message]
[/else]

View file

@ -143,22 +143,27 @@ y={Y}
[/recall]
[message]
description=Owaec
id=msg_cmpgn_ei_06_01
message="Hail, Gweddry!"
[/message]
[message]
description=Gweddry
id=msg_cmpgn_ei_06_02
message="Hello. We have been forced from our positions. Do you think you can help us regain our outpost?"
[/message]
[message]
description=Owaec
id=msg_cmpgn_ei_06_03
message="I am not sure. There are bandits in this country, and it is they who rule this land, not the king. My men are afraid of them, and refuse to come out and fight. As you see, though I have many men, they stay penned up in the keep. The thieves hide in the villages."
[/message]
[message]
description=Dacyn
id=msg_cmpgn_ei_06_04
message="We will see if we can get across to where you are without thieves killing us. Also, we will try to go to the villages and drive the thieves out. Onward, men!"
[/message]
[message]
description=Raklar
id=msg_cmpgn_ei_06_05
message="Stop these intruders from getting through. Ambush them!"
[/message]
[/event]
@ -203,14 +208,17 @@ y={Y}
[then]
[message]
description=Dacyn
id=msg_cmpgn_ei_06_06
message="We have defeated these bandits. Perhaps, now that we are here, Owaec's troops will not be afraid to exit his castle."
[/message]
[message]
description=Gweddry
id=msg_cmpgn_ei_06_07
message="Yes, hopefully. Our outpost has been overrun by undead. What about yours? Have you encountered them?"
[/message]
[message]
description=Owaec
id=msg_cmpgn_ei_06_08
message="No, I have not encountered any undead yet. However, I don't think me and my men can do any more good here. We will come with you to see if, together, we cannot find a way to push back these undead."
[/message]
[endlevel]
@ -233,10 +241,12 @@ y={Y}
[/unit]
[message]
description=Mal-Karhal
id=msg_cmpgn_ei_06_09
message="Hahaha! I have found you, pesky humans! Prepare to die!"
[/message]
[message]
discription=Owaec
id=msg_cmpgn_ei_06_10
message="Oh no! The undead have come, and we have not had time to prepare for them! We will all die now!"
[/message]
[endlevel]

View file

@ -75,14 +75,17 @@ y=10
#endif
[message]
description=Gweddry
id=msg_cmpgn_ei_11_01
message="Look, we have found a pack of Ogres. Lets see if we can capture some to train."
[/message]
[message]
description=Dacyn
id=msg_cmpgn_ei_11_02
message="Alright, we have to keep at least two of these Ogres on the grass until our troops get here to capture them."
[/message]
[message]
description=Owaec
id=msg_cmpgn_ei_11_03
message="We should try to surround them. Gweddry, you stay where you are. Dacyn, you go north-east. I'll go north-west."
[/message]
[teleport]
@ -116,6 +119,7 @@ y=10
[/filter]
[message]
description=Gweddry
id=msg_cmpgn_ei_11_04
message="We have let one escape. Lets hope they all don't!"
[/message]
[kill]
@ -141,6 +145,7 @@ y=10
[then]
[message]
description=Dacyn
id=msg_cmpgn_ei_11_05
message="Good! We have managed to capture some Ogres. We can now recruit them into our army."
[/message]
[allow_recruit]
@ -150,6 +155,7 @@ y=10
[else]
[message]
description=Gweddry
id=msg_cmpgn_ei_11_06
message="We didn't capture enough of the ogres here. We will have to go on without them."
[/message]
[/else]

View file

@ -110,18 +110,22 @@ aggression=0.6
name=start
[message]
description=Mal-Ravanal
id=msg_cmpgn_ei_01_01
message="Come, brothers, let us destroy these humans that stop us from entering Wesnoth!"
[/message]
[message]
description=Mal-Sakkat
id=msg_cmpgn_ei_01_02
message="Since we have no will of our own, we must agree with you."
[/message]
[message]
description=Gweddry
id=msg_cmpgn_ei_01_03
message="No! We must hold this outpost!"
[/message]
[message]
description=Dacyn
id=msg_cmpgn_ei_01_04
message="Sir, we cannot hold out forever. I am going to search the castle and see if there is any way we can escape and warn the King."
[/message]
[kill]
@ -141,6 +145,7 @@ aggression=0.6
[/unit]
[message]
description=Dacyn
id=msg_cmpgn_ei_01_05
message="Sir! We can escape from here now! I have found a trapdoor next to the castle!"
[/message]
@ -159,6 +164,7 @@ aggression=0.6
[/filter]
[message]
description=Gweddry
id=msg_cmpgn_ei_01_06
message="Follow me, men! Through the trapdoor!"
[/message]
[endlevel]
@ -173,6 +179,7 @@ aggression=0.6
name= turn 14
[message]
description=Dacyn
id=msg_cmpgn_ei_01_07
message="Hurry! Before long enemy reinforcements will arrive, and we will all die! Come to the trapdoor!"
[/message]
[/event]
@ -188,6 +195,7 @@ aggression=0.6
[/filter]
[message]
description=Mal-Ravanal
id=msg_cmpgn_ei_01_08
message="You dare to attack ME?!? Go back to your master!"
[/message]
[teleport]

View file

@ -79,54 +79,67 @@
[/recall]
[message]
description=Dacyn
id=msg_cmpgn_ei_12_01
message="Hail, Dwarves! Will you help us defeat these foul Orcs?"
[/message]
[message]
description=Prok-Bak
id=msg_cmpgn_ei_12_02
message="You human! Call us foul, will you?!?!"
[/message]
[message]
description=Pelathsil
id=msg_cmpgn_ei_12_03
message="Why should we help you? You're not a dwarf!"
[/message]
[message]
description=Gweddry
id=msg_cmpgn_ei_12_04
message="Your people helped us in the past, in the tunnels in the South. Why won't you help us now?"
[/message]
[message]
description=Pelathsil
id=msg_cmpgn_ei_12_05
message="Impossible! I can't believe any of my comrades would have helped a human!"
[/message]
[message]
description=Elandin
id=msg_cmpgn_ei_12_06
message="Indeed. Why should any of us help those not in our tribe?"
[/message]
[message]
description=Owaec
id=msg_cmpgn_ei_12_07
message="Will you at least let us pass in safety?"
[/message]
[message]
description=Elandin
id=msg_cmpgn_ei_12_08
message="I am afraid that is now impossible."
[/message]
[message]
description=Prok-Bak
id=msg_cmpgn_ei_12_09
message="Orcs, kill'em all! Humans, elves or dwarves, it don't matter!"
[/message]
[message]
description=Elandin
id=msg_cmpgn_ei_12_10
message="These orcs will die. But so will you, human. You have tresspassed on Elvish land."
[/message]
[message]
description=Pelathsil
id=msg_cmpgn_ei_12_11
message="Oh, elvish land is it now? Die, you elf-dog! And you too, human!"
[/message]
[message]
description=Dacyn
id=msg_cmpgn_ei_12_12
message="These people won't listen to reason, they are blinded by their own races supposed superiority!"
[/message]
[message]
description=Gweddry
id=msg_cmpgn_ei_12_13
message="True. As much as I dislike killing anything that is not evil, it seems we will have to kill these elves, and these dwarves, before they kill us."
[/message]
[/event]
@ -147,6 +160,7 @@ Defeat:
[/filter]
[message]
description=Pelathsil
id=msg_cmpgn_ei_12_14
message="Argh! I'm dead! well, dwarves are still the best!"
[/message]
[gold]
@ -165,6 +179,7 @@ Defeat:
[/filter]
[message]
description=Prok-Bak
id=msg_cmpgn_ei_12_15
message="I die? Orcs rule all!"
[/message]
[gold]
@ -183,6 +198,7 @@ Defeat:
[/filter]
[message]
description=Elandin
id=msg_cmpgn_ei_12_16
message="It seems these darn humans are more powerful than I though. Ugh."
[/message]
[gold]

View file

@ -92,34 +92,42 @@ Defeat:
name=start
[message]
description=Gweddry
id=msg_cmpgn_ei_08_01
message="Look! The road splits here. Which way shall we go?"
[/message]
[message]
description=Owaec
id=msg_cmpgn_ei_08_02
message="I know this area. I was here on an earlier patrol. Just north of here there is a river that leads to the northlands, where orcs live. To the east lies the mountains, then the undead lands."
[/message]
[message]
description=Dacyn
id=msg_cmpgn_ei_08_03
message="We should probably go north to the orcish lands and try to circle around and catch the undead by suprise."
[/message]
[message]
description=Owaec
id=msg_cmpgn_ei_08_04
message="No, I think we should go straight into the undead lands. Strike hard and fast!"
[/message]
[message]
description=Gweddry
id=msg_cmpgn_ei_08_05
message="Either way we will have to fight. Look, the orcs and undead are fighting each other, and block our path!"
[/message]
[message]
description=Mal-Arnai
id=msg_cmpgn_ei_08_06
message="Well, orc, we can either continue this fight, or we can crush there pesky humans and battle later. Your call."
[/message]
[message]
description=Wak-Rano
id=msg_cmpgn_ei_08_07
message="Hm... I know. We will make a pact to destroy these humans, and continue our fight later. (hopefully you will die, for then I will win our battle by default.)"
[/message]
[message]
description=Mal-Arnai
id=msg_cmpgn_ei_08_08
message="Very well, we are allies, for now. (this foolish orc will surely die)."
[/message]
[/event]
@ -131,6 +139,7 @@ Defeat:
[/filter]
[message]
description=Wak-Rano
id=msg_cmpgn_ei_08_09
message="No! These undead has won our battle, and you will be able to enter my northern homeland!"
[/message]
[endlevel]
@ -147,6 +156,7 @@ Defeat:
[/filter]
[message]
description=Mal-Arnai
id=msg_cmpgn_ei_08_10
message="You have entered my master's country! He will not be pleased about this."
[/message]
[endlevel]

View file

@ -74,14 +74,17 @@ Defeat:
[/recall]
[message]
description=Dacyn
id=msg_cmpgn_ei_05_01
message="We have reached the borders of the undead land. Surely you do not mean to go forward- we will all die if we do! We should turn North and help Owaec, captain of the Northern Outpost, hold off the undead."
[/message]
[message]
description=Gweddry
id=msg_cmpgn_ei_05_02
message="I am not yet sure. Whether we go forward or backward, we will have to fight. The necromancer Mal-Skraat has chased us."
[/message]
[message]
description=Mal-Skraat
id=msg_cmpgn_ei_05_03
message="They run from me! Still, it will not help them, the border patrol will destroy them. I may even be promoted!"
[/message]
[/event]
@ -93,10 +96,12 @@ Defeat:
[/filter]
[message]
description=Mal-Skraat
id=msg_cmpgn_ei_05_04
message="Now I will never get promoted!"
[/message]
[message]
description=Dacyn
id=msg_cmpgn_ei_05_05
message="Come, let us return to Wesnoth and aid the Northern Outpost."
[/message]
[endlevel]
@ -113,20 +118,25 @@ Defeat:
[/filter]
[message]
description=Dacyn
id=msg_cmpgn_ei_05_06
message="We have defeated this patrol, but we can still turn back! Do we want to go further into these lands now, or do we want to try to turn back and defeat this necromancer?"
[/message]
[message]
description=Gweddry
id=msg_cmpgn_ei_05_07
message="Hmm..."
[option]
id=msg_cmpgn_ei_05_08
message="We do not want to waste time here fighting Mal-Skraat. Onward!"
[command]
[message]
description=Dacyn
id=msg_cmpgn_ei_05_09
message="I will not say if this is a good decision, but I will follow you."
[/message]
[message]
description=Mal-Skraat
id=msg_cmpgn_ei_05_10
message="Noo!!! I can't be promoted if they run away!"
[/message]
[endlevel]
@ -137,10 +147,12 @@ Defeat:
[/command]
[/option]
[option]
id=msg_cmpgn_ei_05_11
message="You are right. It is foolish to go onward- we must defeat Mal-Skraat and turn back, going to the Northern Outpost."
[command]
[message]
description=Mal-Skraat
id=msg_cmpgn_ei_05_12
message="Good! if I defeat them, I can become a lich!"
[/message]
[/command]
@ -157,6 +169,7 @@ Defeat:
[then]
[message]
description=Dacyn
id=msg_cmpgn_ei_05_13
message="We failed to defeat either enemy! Now more lichs will come, and we will be overwhelmed!"
[/message]
[endlevel]
@ -166,10 +179,12 @@ Defeat:
[else]
[message]
description=Gweddry
id=msg_cmpgn_ei_05_14
message="We cannot spend any more time defeating Mal-Skraat. Like it or not, we must go further into these undead lands."
[/message]
[message]
description=Mal-Skraat
id=msg_cmpgn_ei_05_15
message="Noo!!! He will reach Mal-Ravanal's capital, and I shall be punished for letting him escape!"
[/message]
[endlevel]

View file

@ -61,18 +61,22 @@ Defeat:
[/recall]
[message]
description=Gweddry
id=msg_cmpgn_ei_10_01
message="Look- here is a large river. Should we attempt to cross it, or turn back?"
[/message]
[message]
description=Dacyn
id=msg_cmpgn_ei_10_02
message="We must cross this river. It is said that Ogres live north of here, and we must enlist their aid if we are to defeat the undead. The undead realize this, that is why they have sent a Lich to block our path."
[/message]
[message]
description=Owaec
id=msg_cmpgn_ei_10_03
message="Across this river lies the Northland. Yes, Ogres live there, but so do Orcs, who will try to stop us. We should proceed with caution."
[/message]
[message]
description=Mal-Karanad
id=msg_cmpgn_ei_10_04
message="I will leave your bodies to rot in the river, then I will raise you up to serve in my Master's undead hordes!"
[/message]
[/event]
@ -89,6 +93,7 @@ y=13
name=turn 10
[message]
description=Mal-Karanad
id=msg_cmpgn_ei_10_05
message="I summon from the depths of the river those beasts which will destroy you!"
[/message]
[scroll_to_unit]
@ -117,6 +122,7 @@ y=13
#endif
[message]
description=Dacyn
id=msg_cmpgn_ei_10_06
message="It seems as if in addition to summoning undead this Lich has learned to call up demons!"
[/message]
[/event]

View file

@ -98,34 +98,42 @@ Defeat:
name=start
[message]
description=Gweddry
id=msg_cmpgn_ei_03_01
message="We have escaped from those dark tunnels! But where are we now?"
[/message]
[message]
description=Dacyn
id=msg_cmpgn_ei_03_02
message="Oh no! We are in the middle of enemy territory!"
[/message]
[message]
description=Mal-Kallat
id=msg_cmpgn_ei_03_03
message="Hahaha! We have you surrounded!"
[/message]
[message]
description=Mal-Skraat
id=msg_cmpgn_ei_03_04
message="Why don't we see if the new recruit can handle them. After all, there are only two!"
[/message]
[message]
description=Mal-Tar
id=msg_cmpgn_ei_03_05
message="No!!! They'll kill me!"
[/message]
[message]
description=Mal-Kallat
id=msg_cmpgn_ei_03_06
message="So? We don't care- you're only a Dark Adept."
[/message]
[message]
description=Dacyn
id=msg_cmpgn_ei_03_07
message="It seems Mal-Tar is weak, but his brothers are still surrounding us. I propose we kill him and use his castle as a base for our attack!"
[/message]
[message]
description=Gweddry
id=msg_cmpgn_ei_03_08
message="If we kill Mal-Skraat, we will have opened a way to enter Wesnoth, but if we kill Mal-Kallat, we will be able to penetrate further into Undead lands."
[/message]
[/event]
@ -137,6 +145,7 @@ Defeat:
[/filter]
[message]
description=Mal-Skraat
id=msg_cmpgn_ei_03_09
message="No! You have defeated me, and can re-enter Wesnoth!"
[/message]
[endlevel]
@ -153,6 +162,7 @@ Defeat:
[/filter]
[message]
description=Mal-Skraat
id=msg_cmpgn_ei_03_10
message="You have defeated my brother, but I will follow you and kill you!"
[/message]
[endlevel]

View file

@ -221,38 +221,47 @@ y={Y}
#endif
[message]
description=Konrad II
id=msg_cmpgn_ei_15_01
message="Welcome to Weldyn, Gweddry! Unfortunately we cannot give you as great a welcome as you deserve."
[/message]
[message]
description=Gweddry
id=msg_cmpgn_ei_15_02
message="Thank you, my King Konrad II."
[/message]
[message]
description=Dacyn
id=msg_cmpgn_ei_15_03
message="Well, yes, us being here is all well and good, but there are undead hordes pressing up against our gates. Now what are we going to do about that?"
[/message]
[message]
description=Owaec
id=msg_cmpgn_ei_15_04
message="We need to fight them. Look, night approaches- they will soon attack. I hope we can hold them off."
[/message]
[message]
description=Konrad III
id=msg_cmpgn_ei_15_05
message="I will hold my gate. With my quick and skillful warriors I can resist the undead, at least for a while."
[/message]
[message]
description=Garard III
id=msg_cmpgn_ei_15_06
message="Yes, and my people may be slow, but their blows are the most powerful of all. I can hold my post."
[/message]
[message]
description=Haldric IX
id=msg_cmpgn_ei_15_07
message="Archers are the most powerful fighters of all, as they shall prove in the upcoming battle."
[/message]
[message]
description=Konrad II
id=msg_cmpgn_ei_15_08
message="Peace, my sons! We are fighting the enemy, there is no need for rivalry within our camp."
[/message]
[message]
description=Dacyn
id=msg_cmpgn_ei_15_09
message="In any case, the undead are attacking now. Let us hope we can last out the night."
[/message]
[/event]
@ -264,10 +273,12 @@ y={Y}
[/filter]
[message]
description=Garard III
id=msg_cmpgn_ei_15_10
message="No! These undead have defeated me!"
[/message]
[message]
description=Mal-Trakaax
id=msg_cmpgn_ei_15_11
message="And now we will revive you to serve us, as an undead Knight!"
[/message]
[unit]
@ -280,6 +291,7 @@ y={Y}
[/unit]
[message]
description=Garard III
id=msg_cmpgn_ei_15_12
message="Time to defeat these pesky humans, in my new body."
[/message]
[/event]
@ -290,10 +302,12 @@ y={Y}
[/filter]
[message]
description=Konrad III
id=msg_cmpgn_ei_15_13
message="No! I have been defeated! I only hope the undead do not raise me to fight against you!"
[/message]
[message]
description=Mal-Grekulak
id=msg_cmpgn_ei_15_14
message="Oh, don't worry, we will. Mwahahahahaha!!!"
[/message]
[unit]
@ -306,6 +320,7 @@ y={Y}
[/unit]
[message]
description=Konrad III
id=msg_cmpgn_ei_15_15
message="Well, my one-time father, let us see who will last out the night!"
[/message]
[/event]
@ -314,22 +329,27 @@ y={Y}
name=turn 9
[message]
description=Haldric IX
id=msg_cmpgn_ei_15_16
message="Its difficult to defeat these undead. It will be much easier to join them."
[/message]
[message]
description=Konrad II
id=msg_cmpgn_ei_15_17
message="Huh?"
[/message]
[message]
description=Haldric IX
id=msg_cmpgn_ei_15_18
message="You idiot, I'm defecting!"
[/message]
[message]
description=Gweddry
id=msg_cmpgn_ei_15_19
message="You traitor!"
[/message]
[message]
description=Mal-Uknalu
id=msg_cmpgn_ei_15_20
message="Yes! Now my victory is assured!"
[/message]
[store_unit]
@ -350,6 +370,7 @@ y={Y}
[/gold]
[message]
description=Haldric IX
id=msg_cmpgn_ei_15_21
message="Come, my warriors, let us defeat this foolish King!"
[/message]
[role]
@ -359,6 +380,7 @@ y={Y}
[/role]
[message]
speaker=loyal
id=msg_cmpgn_ei_15_22
message="I don't think so! Our loyalty is with the King!"
[/message]
[/event]
@ -370,10 +392,12 @@ y={Y}
[/filter]
[message]
description=Konrad II
id=msg_cmpgn_ei_15_23
message="I have died, and with me the city shall fall."
[/message]
[message]
description=Haldric IX
id=msg_cmpgn_ei_15_24
message="Now I shall be the king of the undead Wesnoth!"
[/message]
[endlevel]
@ -385,6 +409,7 @@ y={Y}
name=time over
[message]
description=Dacyn
id=msg_cmpgn_ei_15_25
message="Look, the sun has risen. The undead are retreating."
[/message]
[unit]
@ -396,70 +421,87 @@ y={Y}
[/unit]
[message]
description=Mal-Ravanal
id=msg_cmpgn_ei_15_26
message="Well, you have defeated some of my captains. Good job. But that was only a small fraction of my horde."
[/message]
[message]
description=Dacyn
id=msg_cmpgn_ei_15_27
message="What is your point?"
[/message]
[message]
description=Mal-Ravanal
id=msg_cmpgn_ei_15_28
message="Well, it would be very easy for me to defeat you. But I don't think it would do justice to my power."
[/message]
[message]
description=Owaec
id=msg_cmpgn_ei_15_29
message="We don't care about honoring your power. Bring it on!"
[/message]
[message]
decription=Mal-Ravanal
id=msg_cmpgn_ei_15_30
message="Shut up, fool. I meant my own power, not the power of my legions. And that brings me to my second point. You, Gweddry, as a commander, are a coward."
[/message]
[message]
description=Gweddry
id=msg_cmpgn_ei_15_31
message="What, me, a coward!?! Why!?!"
[/message]
[message]
description=Mal-Ravanal
id=msg_cmpgn_ei_15_32
message="Yes, you, a coward. You claim to have defeated my captains, but it was really your hordes, not you."
[/message]
[message]
description=Dacyn
id=msg_cmpgn_ei_15_33
message="Hordes is a name used for undead. We prefer to call ourselves an army."
[/message]
[message]
description=Mal-Ravanal
id=msg_cmpgn_ei_15_34
message="Silence, fool! The point is that Gweddry could not have defeated my minions without the help of his slaves!"
[/message]
[message]
description=Owaec
id=msg_cmpgn_ei_15_35
message="I'm not a slave! And YOU'RE the fool!"
[/message]
[message]
description=Mal-Ravanal
id=msg_cmpgn_ei_15_36
message="SHUT UP! I doubt Gweddry could even last two seconds in actual combat. And I'll prove it. I challenge you, Gweddry, to a duel."
[/message]
[message]
description=Gweddry
id=msg_cmpgn_ei_15_37
message="I'm not going to fight you in one-on-one combat!"
[/message]
[message]
description=Mal-Ravanal
id=msg_cmpgn_ei_15_38
message="That only proves you are a coward. Anyway, who said anything about one-on-one combat? I said a duel, six-on-six. Pick your five best slaves and I will pick my five best minions."
[/message]
[message]
description=Owaec
id=msg_cmpgn_ei_15_39
message="That is a very interesting notion of a duel. Gweddry, I suggest you accept, since he keeps calling you a coward."
[/message]
[message]
description=Dacyn
id=msg_cmpgn_ei_15_40
message="No, don't accept. It is obviously a trick- he will bring many more than five people. We must win this battle on our own terms."
[/message]
[message]
description=Mal-Ravanal
id=msg_cmpgn_ei_15_41
message="I'll make it simple. Accept, or face the onslaught of my hordes, like the coward that you are."
[/message]
[message]
description=Gweddry
id=msg_cmpgn_ei_15_42
message=Hmm...
[option]
name="I'll accept this duel, and prove I am not a coward once and for all."

View file

@ -5,6 +5,7 @@
[/filter]
[message]
description=Gweddry
id=msg_cmpgn_ei_death_gweddry
message="No! I have failed in my mission to save Wesnoth from destruction!"
[/message]
[endlevel]
@ -19,6 +20,7 @@
[/filter]
[message]
description=Dacyn
id=msg_cmpgn_ei_death_dacyn
message="Wesnoth is doomed! Without me, Gweddry has no hope!"
[/message]
[endlevel]
@ -33,10 +35,12 @@
[/filter]
[message]
description=Owaec
id=msg_cmpgn_ei_death_owaec1
message="My outpost has fallen..."
[/message]
[message]
description=Owaec
id=msg_cmpgn_ei_death_owaec2
message="ugh."
[/message]
[endlevel]

View file

@ -167,12 +167,12 @@ Defeat:
[command]
[message]
description=Konrad
id=msg11_4
id=msg11_5e
message="This old mine seems to be connected to the main tunnels."
[/message]
[message]
description=Kalenz
id=msg11_5b
id=msg11_5f
message="I am hesitant to enter. It will be so difficult in the darkness!"
[/message]
[message]

View file

@ -171,7 +171,7 @@ simple_targetting=yes
canrecruit=1
recruit=Elvish Fighter,Elvish Archer,Elvish Ranger
[ai]
recruitment_pattern=fighter,archer
recruitment_pattern=fighter,archer,mixed fighter
[/ai]
gold=200
team_name=elves
@ -184,7 +184,7 @@ simple_targetting=yes
canrecruit=1
recruit=Elvish Shaman,Elvish Archer,Elvish Fighter
[ai]
recruitment_pattern=archer,fighter
recruitment_pattern=archer,archer,fighter,fighter,healer
[/ai]
gold=200
team_name=elves

View file

@ -206,7 +206,7 @@ Defeat:
message="What is that?"
[/message]
[message]
id=msg9_a4
id=msg9_a3
description=Kalenz
message="Creatures of the deep are upon us! This may be very dangerous. Be quick! We must get to the other side with all haste!"
[/message]

View file

@ -335,14 +335,14 @@ Defeat:
[message]
id=hasty_15
speaker=narrator
message="You receive 500 pieces of gold!"
message="You receive 200 pieces of gold!"
[/message]
[/command]
[command]
[gold]
side=1
amount=500
amount=200
[/gold]
[/command]

View file

@ -413,16 +413,16 @@ Defeat
[/command]
[command]
[message]
id=msg12_27
id=msg12_27a
description=Geldar
message="You are right, friend. I will put my best men at your disposal. We know not where the Scepter is though. Legend says it is hidden in the northern tunnels."
message="You are right, friend. I will put my best men at your disposal. We know not where the Scepter is though. Legend says it is hidden in the eastern tunnels."
[/message]
[/command]
[command]
[message]
id=msg12_28
id=msg12_28a
description=Delfador
message="Then to the northern tunnels we shall go!"
message="Then to the eastern tunnels we shall go!"
[/message]
[/command]
[command]

View file

@ -11,7 +11,7 @@ next_scenario=A_Choice_Must_Be_Made
name=The Sceptre of Fire
id=Sceptre
map_data="{maps/Heir_To_The_Throne/Sceptre}"
turns=60
turns=40
victory_when_enemies_defeated=no
{UNDERGROUND}
@ -113,7 +113,7 @@ Defeat:
recruit=Goblin Knight,Wolf Rider,Troll,Orcish Warrior,Orcish Crossbow
team_name=orcs
{GOLD 80 150 200}
{GOLD 30 50 90}
{INCOME 5 10 20}
[/side]
[/items]
@ -149,7 +149,7 @@ Defeat:
recruit=Troll,Troll Warrior,Ogre
#endif
team_name=orcs
{GOLD 80 150 200}
{GOLD 30 50 80}
{INCOME 5 10 20}
[/side]
[/items]
@ -196,11 +196,11 @@ Defeat:
#ifdef EASY
recruit=Troll,Ogre,Goblin Knight,Wolf Rider,Troll Whelp
#else
recruit=Troll,Troll Warrior,Ogre,Goblin Knight,Wolf Rider,Troll Whelp
recruit=Troll,Troll Warrior,Ogre,Goblin Knight,Wolf Rider,Troll Whelp,Saurian
#endif
team_name=orcs
{GOLD 80 150 200}
{GOLD 30 60 120}
{INCOME 5 10 20}
[/side]
[/items]
@ -225,10 +225,10 @@ Defeat:
#ifdef EASY
recruit=Troll,Ogre,Goblin Knight,Wolf Rider,Troll Whelp
#else
recruit=Troll,Troll Warrior,Ogre,Goblin Knight,Wolf Rider,Troll Whelp
recruit=Troll,Troll Warrior,Ogre,Goblin Knight,Wolf Rider,Troll Whelp,Saurian
#endif
team_name=orcs
{GOLD 80 150 200}
{GOLD 40 70 150}
{INCOME 5 10 20}
[/side]
[/items]

View file

@ -55,9 +55,9 @@ Defeat:
canrecruit=1
recruit=Orcish Warrior,Wolf Rider,Troll,Troll Whelp,Goblin Pillager
#ifdef HARD
gold=300
gold=500
#else
gold=200
gold=350
#endif
team_name=evil
[/side]
@ -284,7 +284,7 @@ Defeat:
[/filter]
[message]
id=msg13_9d
description=Konrad
speaker=second_unit
message="I did not know that the undead were in these pits!"
[/message]
[/event]
@ -350,9 +350,9 @@ Defeat:
message="Rest in peace, Lionel. The poor, lost general."
[/message]
[message]
id=msg13_die3
id=msg13_die3a
description=Lionel
message="I am destroyed, but my mission must be completed. Though you are foes, you are at least worthy ones, so I will tell you that the Scepter is further north from here, deep in the caverns. May you have better fortune in your quest than I did!"
message="I am destroyed, but my mission must be completed. Though you are foes, you are at least worthy ones, so I will tell you that the Scepter is east from here, the way you have come from, deep in the caverns. I made the mistake of not asking for directions when I became lost. May you have better fortune in your quest than I did!"
[/message]
[/event]

View file

@ -4,7 +4,7 @@
[multiplayer]
name="Siege Castles"
map=castles
map_data="{maps/Multiplayer/Castles}"
turns=90
id=multiplayer_castles

View file

@ -76,6 +76,25 @@
{TERRAIN_BASE ~ fog}
{TERRAIN_BASE ( ) void}
#
# Villages
#
{TERRAIN_BASE Y swampwater}
{BUILDING Y village-swampwater}
{TERRAIN_BASE V snow}
{BUILDING V village-snow}
{TERRAIN_BASE Z coast}
{BUILDING Z village-coast}
{TERRAIN_BASE v grassland}
{BUILDING v village-human}
{TERRAIN_BASE D cave}
{BUILDING D village-cave}
{TERRAIN_BASE t grassland}
{BUILDING t village}
#
# Transition between terrains
#
@ -135,24 +154,6 @@ K
{TERRAIN_ADJACENT_1 s !s ocean}
#
# Villages
#
{TERRAIN_BASE Y swampwater}
{BUILDING Y village-swampwater}
{TERRAIN_BASE V snow}
{BUILDING V village-snow}
{TERRAIN_BASE Z coast}
{BUILDING Z village-coast}
{TERRAIN_BASE v grassland}
{BUILDING v village-human}
{TERRAIN_BASE D cave}
{BUILDING D village-cave}
{TERRAIN_BASE t grassland}
{BUILDING t village}
# Some test cases

View file

@ -15,7 +15,7 @@ width=800
height=600
[main_map]
rect=0,26,887,768
rect=0,26,882,768
xanchor=left
yanchor=top
[/main_map]
@ -23,7 +23,7 @@ height=600
[menu]
title=main_menu
image=lite
items=speak,objectives,unitlist,recruit,recall,statustable,endturn,undo,redo,save,load,statistics,preferences,help,quit
items=speak,objectives,unitlist,recruit,recall,statustable,endturn,undo,redo,save,load,statistics,preferences,chatlog,help,quit
rect=3,1,100,22
xanchor=fixed
yanchor=fixed
@ -60,24 +60,24 @@ height=600
# rightside panel
[panel]
image=misc/rightside.png
rect=887,24,1024,284
rect=882,25,1024,309
xanchor=right
yanchor=fixed
[/panel]
[mini_map]
rect=900,32,1016,177
rect=892,32,1017,175
xanchor=right
yanchor=fixed
[/mini_map]
[panel]
image=misc/rightside-bg.png
rect=887,284,1024,768
rect=882,309,1024,730
xanchor=right
yanchor=top
[/panel]
[panel]
image=misc/rightside-bottom.png
rect=887,713,0,768
rect=882,730,0,768
xanchor=right
yanchor=bottom
[/panel]
@ -85,7 +85,7 @@ height=600
[menu]
title=action_endturn
items=endturn
rect=904,736
rect=900,738
xanchor=right
yanchor=bottom
[/menu]
@ -127,6 +127,22 @@ height=600
yanchor=fixed
[/panel]
# HP/XP
[label]
font_size=10
text=hp
rect=967,234,1022,246
xanchor=right
yanchor=fixed
[/label]
[label]
font_size=10
text=xp
rect=967,260,1022,272
xanchor=right
yanchor=fixed
[/label]
# gold icon
[label]
icon=misc/gold.png
@ -171,7 +187,7 @@ height=600
[status]
# the time of day image
[time_of_day]
rect=900,185,1017,225
rect=892,184,1017,223
xanchor=right
yanchor=fixed
[/time_of_day]
@ -254,25 +270,25 @@ height=600
#unit stats here
[unit_image]
rect=900,235,946,283
rect=891,235,963,307
xanchor=right
yanchor=fixed
[/unit_image]
[unit_description]
font_size=14
rect=900,290,1020,308
rect=891,312,1022,330
xanchor=right
yanchor=fixed
[/unit_description]
[unit_type]
font_size=12
rect=900,308,1020,324
rect=891,330,1022,346
xanchor=right
yanchor=fixed
[/unit_type]
[unit_level]
font_size=12
rect=900,324,1020,340
rect=891,346,1022,362
prefix=level
prefix_literal=" "
xanchor=right
@ -280,31 +296,32 @@ height=600
[/unit_level]
[unit_alignment]
font_size=12
rect=900,340,1020,356
rect=891,362,1022,378
xanchor=right
yanchor=fixed
[/unit_alignment]
[unit_traits]
font_size=12
rect=900,356,1020,372
rect=891,378,1022,394
xanchor=right
yanchor=fixed
[/unit_traits]
[unit_abilities]
font_size=12
rect=900,372,1020,388
rect=891,394,1022,410
xanchor=right
yanchor=fixed
[/unit_abilities]
[unit_status]
font_size=12
rect=958,241,1008,291
#rect=958,241,1008,291
rect=968,289,1020,305
xanchor=right
yanchor=fixed
[/unit_status]
[unit_moves]
font_size=12
rect=900,404,1020,420
rect=891,410,1022,426
prefix=movement
prefix_literal=": "
xanchor=right
@ -312,23 +329,28 @@ height=600
[/unit_moves]
[unit_hp]
font_size=12
rect=900,420,1020,436
prefix=hp
prefix_literal=": "
rect=967,246,1022,260
#prefix=hp
#prefix_literal=" "
#prefix=""
#prefix_literal=""
xanchor=right
yanchor=fixed
[/unit_hp]
[unit_xp]
font_size=12
rect=900,436,1020,452
prefix=xp
prefix_literal=": "
rect=967,272,1022,286
#prefix=xp
#prefix_literal=" "
#prefix=""
#prefix_literal=""
xanchor=right
yanchor=fixed
[/unit_xp]
[unit_weapons]
font_size=12
rect=900,452,1020,620
#rect=900,452,1020,620
rect=891,426,1022,594
xanchor=right
yanchor=fixed
[/unit_weapons]

View file

@ -4,7 +4,7 @@
[mask]
name=castle-convex-ne
image=mask-castle-ne.png
shift=-18,-45
shift=-18,-36
[/mask]
[mask]
@ -34,7 +34,7 @@
[mask]
name=castle-convex-nw
image=mask-castle-nw.png
shift=-36,-45
shift=-36,-36
[/mask]
@ -43,7 +43,7 @@
[mask]
name=castle-concave-ne
image=mask-castle-ne.png
shift=-18,-45
shift=-18,-36
[/mask]
[mask]
@ -73,6 +73,6 @@
[mask]
name=castle-concave-nw
image=mask-castle-nw.png
shift=-36,-45
shift=-36,-36
[/mask]

View file

@ -562,6 +562,7 @@ action_updateshroud="Update Shroud Now"
action_continue="Continue Move"
action_search="Find Label or Unit"
action_help="Help"
action_chatlog="View Chat Log"
action_editnewmap="New Map"
action_editloadmap="Load Map"
action_editsavemap="Save Map"
@ -587,6 +588,7 @@ hotkey_already_used="This HotKey is already in use."
profile="Profile"
speak_allies_only="Send to allies only"
chat_log="Chat Log"
speed="Speed:"
speed_normal="Normal"
@ -733,8 +735,11 @@ red="Red"
blue="Blue"
green="Green"
yellow="Yellow"
pink="Pink"
purple="Purple"
orange="Orange"
grey="Grey"
white="White"
brown="Brown"
#terrain
terrain="Terrain"

View file

@ -14,7 +14,7 @@ alignment=neutral
advanceto=null
cost=80
ability=ambush
usage=scout
usage=mixed fighter
unit_description="Elvish Avengers are extremely skillful and extremely quick, powerful in all forms of combat. Avengers are considered the best of all woodsmen in Wesnoth, and can ambush their foes in the forest, because they cannot be seen in the woods until just after they have attacked."
get_hit_sound=groan.wav
[attack]

View file

@ -15,7 +15,7 @@ level=2
alignment=neutral
advanceto=Elvish Marshal
cost=40
usage=mixed fighter
usage=fighter
unit_description="Skilled in commanding soldiers, Elvish Captains provide a bonus to all level-1 units on adjacent hexes. Captains are also skilled in both short- and long-range fighting."
get_hit_sound=groan.wav
[attack]

View file

@ -13,7 +13,7 @@ level=3
alignment=neutral
advanceto=null
cost=100
usage=mixed fighter
usage=fighter
unit_description="Elvish Champions are awesome masters of swordsmanship, inflicting large amounts of damage in close combat. Master fighters, they are also adept with the bow, able to inflict damage on their enemies from both near and far."
get_hit_sound=groan.wav
[attack]

View file

@ -13,7 +13,7 @@ level=2
alignment=neutral
advanceto=Elvish Champion
cost=40
usage=mixed fighter
usage=fighter
unit_description="Elvish Heroes focus on individual performance on the battlefield, having tweaked their combat skills to the very maximum. Elvish Heroes prefer fighting at close range with the sword, but are also skilled at the bow."
get_hit_sound=groan.wav
[attack]

View file

@ -12,7 +12,7 @@ level=2
alignment=neutral
advanceto=Elvish Sharpshooter
cost=60
usage=scout
usage=archer
unit_description="Elvish Marksman are expert in use of the bow. Their skill guarantees them a 60% chance to hit enemies, even those hidden in difficult terrain. This great skill with the bow compensates for their lack of skill in melee combat and lesser speed."
get_hit_sound=groan.wav
[attack]

View file

@ -16,7 +16,7 @@ level=3
alignment=neutral
advanceto=null
cost=80
usage=mixed fighter
usage=fighter
unit_description="Possessing one of the highest ranks in the Elven military, Elvish Marshals can lead any level 1 or 2 units in adjacent hexes, causing them to fight with increased skill. Marshals are also themselves greatly skilled in fighting, with both the sword and the bow."
get_hit_sound=groan.wav
[attack]

View file

@ -11,7 +11,7 @@ level=2
alignment=neutral
advanceto=Elvish Avenger
cost=40
usage=scout
usage=mixed fighter
ability=ambush
unit_description="Elvish Rangers are quick and powerful. Skilled in both short- and long-range combat, Rangers are truly all-round fighters. The best of all woodsmen, Rangers cannot be seen by enemies while they are in forest, unless they have just made an attack, or there are enemies adjacent to them."
get_hit_sound=groan.wav

View file

@ -11,7 +11,7 @@ level=3
alignment=neutral
advanceto=null
cost=90
usage=scout
usage=archer
unit_description="The most elite archers in all of Wesnoth, Elvish Sharpshooters are incredibly accurate, guaranteed a 60% chance to hit when attacking, even when firing very quickly. Sharpshooters are excellent at picking off entrenched enemies."
get_hit_sound=groan.wav
[attack]

View file

@ -300,6 +300,10 @@ wesnoth_editor_SOURCES = editor/editor.cpp \
widgets/widget.hpp
AM_CXXFLAGS = @SDL_CFLAGS@ -DWESNOTH_PATH=\"$(pkgdatadir)\" -DLOCALEDIR=\"$(localedir)\"
if X11
CXXFLAGS += -D_X11 @X_CFLAGS@
endif
if GCC
CXXFLAGS += -fno-omit-frame-pointer
endif

View file

@ -198,10 +198,11 @@ std::vector<std::string> get_text() {
text.push_back("- wint3r");
text.push_back("+ ");
text.push_back("+Past Contributors");
text.push_back("+Contributors");
text.push_back("- edge");
text.push_back("- Frédéric Wagner");
text.push_back("- Jan Zvánovec (jaz)");
text.push_back("- Maksim Orlovich (SadEagle)");
text.push_back("+ ");
return text;
}

View file

@ -1443,6 +1443,7 @@ bool clear_shroud_unit(const gamemap& map,
for(std::vector<gamemap::location>::const_iterator it =
cleared_locations.begin(); it != cleared_locations.end(); ++it) {
if(units.count(*it)) {
if(seen_units == NULL || known_units == NULL) {
static const std::string sighted("sighted");
@ -1757,6 +1758,10 @@ size_t move_unit(display* disp, const game_data& gamedata,
disp->recalculate_minimap();
}
for(std::set<gamemap::location>::const_iterator seen = seen_units.begin(); seen != seen_units.end(); ++seen) {
game_events::fire("sighted",*seen,steps.back());
}
assert(steps.size() <= route.size());
return steps.size();

View file

@ -1,16 +1,345 @@
#include "clipboard.hpp"
#ifdef _X11
#define CLIPBOARD_FUNCS_DEFINED
#include <X11/Xlib.h>
#include <unistd.h>
#include <iostream>
#include "SDL_syswm.h"
/**
The following are two classes which wrap the SDL's interface to X, including
locking/unlocking, and which manage the atom internment. They exist mainly to make
the actual clipboard code somewhat readable
*/
class XHelper
{
private:
XHelper()
{
acquireCount_ = 0;
acquire();
//Intern some atoms;
const char* atoms[] = {
"CLIPBOARD",
"TEXT",
"COMPOUND_TEXT",
"UTF8_STRING",
"WESNOTH_PASTE",
"TARGETS"
};
XInternAtoms(dpy(), (char**)atoms, 6, false, atomTable_);
release();
}
static XHelper* s_instance_;
SDL_SysWMinfo wmInf_;
Atom atomTable_[6];
int acquireCount_;
public:
static XHelper* instance()
{
if (!s_instance_)
s_instance_ = new XHelper;
return s_instance_;
}
Atom XA_CLIPBOARD()
{
return atomTable_[0];
}
Atom XA_TEXT()
{
return atomTable_[1];
}
Atom XA_COMPOUND_TEXT()
{
return atomTable_[2];
}
Atom UTF8_STRING()
{
return atomTable_[3];
}
Atom WES_PASTE()
{
return atomTable_[4];
}
Atom XA_TARGETS()
{
return atomTable_[5];
}
Display* dpy()
{
return wmInf_.info.x11.display;
}
Window window()
{
return wmInf_.info.x11.window;
}
void acquire(void)
{
++acquireCount_;
if (acquireCount_ == 1) {
SDL_VERSION (&wmInf_.version);
SDL_GetWMInfo(&wmInf_);
wmInf_.info.x11.lock_func();
}
}
void release(void)
{
--acquireCount_;
if (acquireCount_ == 0)
wmInf_.info.x11.unlock_func();
}
};
XHelper* XHelper::s_instance_ = 0;
class UseX
{
public:
UseX()
{
XHelper::instance()->acquire();
}
~UseX()
{
XHelper::instance()->release();
}
XHelper* operator->()
{
return XHelper::instance();
}
};
/**
Note: unfortunately, SDL does not keep track of event timestamps.
This means we are forced to use CurrentTime in many spots and are
unable to perform many safety checks. Hence, the code below is
not compliant to the ICCCM, and may ocassionally suffer from
race conditions if an X client is connected to the server over
a slow/high-latency link. This implementation is also very minimal.
The text is assumed to be reasonably small as INCR transactions are not
supported. MULTIPLE is not supported either.
We provide UTF8_STRING, COMPOUND_TEXT, and TEXT, and
try to grab all of them, plus STRING (which is latin1).
*/
/**
We primarily. keep a copy of the string to response to data requests,
but it also has an another function: in case we're both the source
and destination, we just copy it accross; this is so that we
don't have to handle SelectionRequest events while waiting for SelectionNotify.
To make this work, however, this gets cleared when we loose CLIPBOARD
*/
static std::string clipboard_string;
void handle_system_event(const SDL_Event& event)
{
XEvent& xev = event.syswm.msg->event.xevent;
if (xev.type == SelectionRequest) {
UseX x11;
//Since wesnoth does not notify us of selections,
//we set both selection + clipboard when copying.
if ((xev.xselectionrequest.owner == x11->window()) &&
((xev.xselectionrequest.selection == XA_PRIMARY) ||
(xev.xselectionrequest.selection == x11->XA_CLIPBOARD()))) {
XEvent responseEvent;
responseEvent.xselection.type = SelectionNotify;
responseEvent.xselection.display = x11->dpy();
responseEvent.xselection.requestor = xev.xselectionrequest.requestor;
responseEvent.xselection.selection = xev.xselectionrequest.selection;
responseEvent.xselection.target = xev.xselectionrequest.target;
responseEvent.xselection.property = None; //nothing available, by default
responseEvent.xselection.time = xev.xselectionrequest.time;
//std::cout<<"Request for target:"<<XGetAtomName(x11->dpy(), xev.xselectionrequest.target)<<"\n";
//### presently don't handle XA_STRING as it must be latin1
if (xev.xselectionrequest.target == x11->XA_TARGETS()) {
responseEvent.xselection.property = xev.xselectionrequest.property;
Atom supported[] = {
x11->XA_TEXT(),
x11->XA_COMPOUND_TEXT(),
x11->UTF8_STRING(),
x11->XA_TARGETS()
};
XChangeProperty(x11->dpy(), responseEvent.xselection.requestor,
xev.xselectionrequest.property, XA_ATOM, 32, PropModeReplace,
(unsigned char*)supported, 4);
}
//The encoding of XA_TEXT and XA_COMPOUND_TEXT is not specified
//by the ICCCM... So we assume wesnoth native/utf-8 for simplicity.
//modern apps are going to use UTF8_STRING anyway
if (xev.xselectionrequest.target == x11->XA_TEXT() ||
xev.xselectionrequest.target == x11->XA_COMPOUND_TEXT() ||
xev.xselectionrequest.target == x11->UTF8_STRING()) {
responseEvent.xselection.property = xev.xselectionrequest.property;
XChangeProperty(x11->dpy(), responseEvent.xselection.requestor,
xev.xselectionrequest.property,
xev.xselectionrequest.target, 8, PropModeReplace,
(const unsigned char*) clipboard_string.c_str(), clipboard_string.length());
}
XSendEvent(x11->dpy(), xev.xselectionrequest.requestor, False, NoEventMask,
&responseEvent);
}
}
if (xev.type == SelectionClear) {
UseX x11;
if (xev.xselectionclear.selection == x11->XA_CLIPBOARD())
clipboard_string = ""; //We no longer own the clipboard, don't try in-process C&P
}
}
void copy_to_clipboard(const std::string& text)
{
if (text.empty()) {
return;
}
clipboard_string = text;
UseX x11;
XSetSelectionOwner(x11->dpy(), XA_PRIMARY, x11->window(), CurrentTime);
XSetSelectionOwner(x11->dpy(), x11->XA_CLIPBOARD(), x11->window(), CurrentTime);
}
//Tries to grab a given target. Returns true if successful, false otherwise
static bool try_grab_target(Atom target, std::string& ret)
{
UseX x11;
//Cleanup previous data
XDeleteProperty(x11->dpy(), x11->window(), x11->WES_PASTE());
XSync (x11->dpy(), False);
//std::cout<<"We request target:"<<XGetAtomName(x11->dpy(), target)<<"\n";
//Request information
XConvertSelection(x11->dpy(), x11->XA_CLIPBOARD(), target,
x11->WES_PASTE(), x11->window(), CurrentTime);
//Wait (with timeout) for a response SelectionNotify
for (int attempt = 0; attempt < 15; attempt++) {
if (XPending(x11->dpy())) {
XEvent selectNotify;
while (XCheckTypedWindowEvent(x11->dpy(), x11->window(), SelectionNotify, &selectNotify)) {
if (selectNotify.xselection.property == None)
//Not supported. Say so.
return false;
else if (selectNotify.xselection.property == x11->WES_PASTE() &&
selectNotify.xselection.target == target) {
//The size
unsigned long length = 0;
unsigned char* data;
//these 3 XGetWindowProperty returns but we don't use
Atom typeRet;
int formatRet;
unsigned long remaining;
// std::cout<<"Grab:"<<XGetAtomName(x11->dpy(), target)<<"\n";
//Grab the text out of the property
XGetWindowProperty(x11->dpy(), x11->window(),
selectNotify.xselection.property,
0, 65535/4, True, target,
&typeRet, &formatRet, &length, &remaining, &data);
if (data && length) {
ret = (char*)data;
XFree(data);
return true;
} else {
return false;
}
}
}
}
usleep(10000);
}
//Timed out -- return empty string
return false;
}
std::string copy_from_clipboard()
{
if (!clipboard_string.empty())
return clipboard_string; //in-wesnoth copy-paste
std::string ret;
UseX x11;
if (try_grab_target(x11->UTF8_STRING(), ret))
return ret;
if (try_grab_target(x11->XA_COMPOUND_TEXT(), ret))
return ret;
if (try_grab_target(x11->XA_TEXT(), ret))
return ret;
if (try_grab_target(XA_STRING, ret)) //acroread only provides this
return ret;
return "";
}
#endif
#ifdef WIN32
#include <windows.h>
#endif
#define CLIPBOARD_FUNCS_DEFINED
void handle_system_event(const SDL_Event& )
{}
void copy_to_clipboard(const std::string& text)
{
if(text.empty()) {
return;
}
#ifdef WIN32
if(!OpenClipboard(0)) {
return;
}
@ -24,12 +353,10 @@ void copy_to_clipboard(const std::string& text)
GlobalUnlock(clip_buffer);
SetClipboardData(CF_TEXT,clip_buffer);
CloseClipboard();
#endif
}
std::string copy_from_clipboard()
{
#ifdef WIN32
if(OpenClipboard(NULL)) {
const HANDLE data = GetClipboardData(CF_TEXT);
char* const buffer = reinterpret_cast<char*>(GlobalLock(data));
@ -38,7 +365,21 @@ std::string copy_from_clipboard()
return buffer;
}
#endif
return "";
}
#endif
#ifndef CLIPBOARD_FUNCS_DEFINED
void copy_to_clipboard(const std::string& text)
{
}
std::string copy_from_clipboard()
{
return "";
}
#endif

View file

@ -2,8 +2,13 @@
#define CLIPBOARD_HPP_INCLUDED
#include <string>
#include "SDL.h"
void copy_to_clipboard(const std::string& text);
std::string copy_from_clipboard();
#endif
#ifdef _X11
void handle_system_event(const SDL_Event& ev);
#endif
#endif

View file

@ -45,25 +45,37 @@ void advance_unit(const game_data& info,
if(u == units.end() || u->second.advances() == false)
return;
std::cerr << "advance_unit: " << u->second.type().name() << "\n";
const std::vector<std::string>& options = u->second.type().advances_to();
std::vector<std::string> lang_options;
std::vector<unit> sample_units;
for(std::vector<std::string>::const_iterator op = options.begin();
op != options.end(); ++op) {
for(std::vector<std::string>::const_iterator op = options.begin(); op != options.end(); ++op) {
sample_units.push_back(::get_advanced_unit(info,units,loc,*op));
const unit_type& type = sample_units.back().type();
lang_options.push_back("&" + type.image() + "," + type.language_name());
}
const config::child_list& mod_options = u->second.get_modification_advances();
for(config::child_list::const_iterator mod = mod_options.begin(); mod != mod_options.end(); ++mod) {
sample_units.push_back(::get_advanced_unit(info,units,loc,u->second.type().name()));
sample_units.back().add_modification("advance",**mod);
const unit_type& type = sample_units.back().type();
lang_options.push_back("&" + type.image() + "," + translate_string_default("advance_" + (**mod)["id"],(**mod)["description"]));
}
std::cerr << "options: " << options.size() << "\n";
int res = 0;
if(options.empty()) {
if(lang_options.empty()) {
return;
} else if(random_choice) {
res = rand()%options.size();
} else if(options.size() > 1) {
res = rand()%lang_options.size();
} else if(lang_options.size() > 1) {
const events::event_context dialog_events_context;
unit_preview_pane unit_preview(gui,&map,sample_units);
@ -77,6 +89,7 @@ void advance_unit(const game_data& info,
recorder.choose_option(res);
std::cerr << "animating advancement...\n";
animate_unit_advancement(info,units,loc,gui,size_t(res));
}
@ -90,7 +103,9 @@ bool animate_unit_advancement(const game_data& info,unit_map& units, gamemap::lo
}
const std::vector<std::string>& options = u->second.type().advances_to();
if(choice >= options.size()) {
const config::child_list& mod_options = u->second.get_modification_advances();
if(choice >= options.size() + mod_options.size()) {
return false;
}
@ -107,7 +122,13 @@ bool animate_unit_advancement(const game_data& info,unit_map& units, gamemap::lo
}
}
::advance_unit(info,units,loc,options[choice]);
const std::string& chosen_unit = choice < options.size() ? options[choice] : u->second.type().name();
::advance_unit(info,units,loc,chosen_unit);
u = units.find(loc);
if(u != units.end() && choice >= options.size()) {
u->second.add_modification("advance",*mod_options[choice - options.size()]);
}
gui.invalidate_unit();
@ -594,7 +615,7 @@ namespace {
}
unit_preview_pane::unit_preview_pane(display& disp, const gamemap* map, const unit& u, TYPE type, bool on_left_side)
: gui::preview_pane(disp), details_button_(disp,translate_string("profile"),gui::button::TYPE_PRESS,"lite",gui::button::MINIMUM_SPACE),
: gui::preview_pane(disp), details_button_(disp,translate_string("profile"),gui::button::TYPE_PRESS,"lite_small",gui::button::MINIMUM_SPACE),
map_(map), units_(&unit_store_), index_(0), left_(on_left_side),
weapons_(type == SHOW_ALL)
{
@ -603,7 +624,7 @@ unit_preview_pane::unit_preview_pane(display& disp, const gamemap* map, const un
}
unit_preview_pane::unit_preview_pane(display& disp, const gamemap* map, const std::vector<unit>& units, TYPE type, bool on_left_side)
: gui::preview_pane(disp), details_button_(disp,translate_string("profile"),gui::button::TYPE_PRESS,"lite",gui::button::MINIMUM_SPACE),
: gui::preview_pane(disp), details_button_(disp,translate_string("profile"),gui::button::TYPE_PRESS,"lite_small",gui::button::MINIMUM_SPACE),
map_(map), units_(&units), index_(0), left_(on_left_side),
weapons_(type == SHOW_ALL)
{
@ -714,7 +735,7 @@ void unit_preview_pane::draw()
details << string_table["hp"] << ": " << u.hitpoints()
<< "/" << u.max_hitpoints() << "\n";
if(u.type().advances_to().empty()) {
if(u.can_advance() == false) {
details << string_table["xp"] << ": " << u.experience() << "/-";
} else {
//if killing a unit the same level as us would level us up,

View file

@ -841,7 +841,7 @@ void display::draw_unit_details(int x, int y, const gamemap::location& loc,
details << string_table["hp"] << ": " << u.hitpoints()
<< "/" << u.max_hitpoints() << "\n";
if(u.type().advances_to().empty()) {
if(u.can_advance() == false) {
details << string_table["xp"] << ": " << u.experience() << "/-";
} else {
//if killing a unit the same level as us would level us up,
@ -1219,10 +1219,10 @@ void display::draw_unit_on_tile(int x, int y, SDL_Surface* unit_image_override,
draw_bar(*energy_file,xpos,ypos,(u.max_hitpoints()*2)/3,unit_energy,energy_colour,bar_alpha);
}
if(u.experience() > 0 && u.type().can_advance()) {
if(u.experience() > 0 && u.can_advance()) {
const double filled = double(u.experience())/double(u.max_experience());
const int level = maximum<int>(u.type().level(),1);
const SDL_Color normal_colour = {173,200,248,0}, near_advance_colour = {255,255,255,0};
const SDL_Color normal_colour = {02,153,255,0}, near_advance_colour = {255,255,255,0};
const bool near_advance = u.max_experience() - u.experience() <= game_config::kill_experience*level;
const SDL_Color colour = near_advance ? near_advance_colour : normal_colour;

View file

@ -1,3 +1,4 @@
#include "clipboard.hpp"
#include "cursor.hpp"
#include "events.hpp"
#include "mouse.hpp"
@ -279,6 +280,14 @@ void pump()
break;
}
#ifdef _X11
case SDL_SYSWMEVENT: {
//clipboard support for X11
handle_system_event(event);
break;
}
#endif
case SDL_QUIT: {
throw CVideo::quit();

View file

@ -116,7 +116,7 @@ struct font_style_setter
//SDL_ttf to segfault. We work around this here by disallowing combinations
//of styles
if((style&TTF_STYLE_UNDERLINE) != 0) {
style = TTF_STYLE_UNDERLINE;
style = TTF_STYLE_NORMAL; //TTF_STYLE_UNDERLINE;
} else if((style&TTF_STYLE_BOLD) != 0) {
style = TTF_STYLE_BOLD;
} else if((style&TTF_STYLE_ITALIC) != 0) {
@ -368,7 +368,7 @@ SDL_Rect draw_text_line(SDL_Surface *gui_surface, const SDL_Rect& area, int size
SDL_Rect src = dest;
src.x = 0;
src.y = 0;
sdl_safe_blit(surface,&src,gui_surface,&dest);
SDL_BlitSurface(surface,&src,gui_surface,&dest);
}
if(use_tooltips) {

View file

@ -472,6 +472,9 @@ int play_game(int argc, char** argv)
}
const cursor::manager cursor_manager;
#ifdef _X11
SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
#endif
std::cerr << "initialized gui\n";
std::cerr << (SDL_GetTicks() - start_ticks) << "\n";

View file

@ -739,7 +739,12 @@ bool event_handler::handle_event_command(const queued_event& event_info, const s
gamemap::location loc;
bool remove_overlay = false;
if(filter != NULL) {
loc = gamemap::location(*filter);
for(unit_map::const_iterator u = units->begin(); u != units->end(); ++u) {
if(game_events::unit_matches_filter(u,*filter)) {
loc = u->first;
break;
}
}
}
if(loc.valid() == false) {
@ -749,10 +754,7 @@ bool event_handler::handle_event_command(const queued_event& event_info, const s
const unit_map::iterator u = units->find(loc);
if(u == units->end())
return rval;
if(filter == NULL || u->second.matches_filter(*filter)) {
if(u != units->end() && (filter == NULL || u->second.matches_filter(*filter))) {
const std::string& lang = string_table[id];
if(!lang.empty())
text = lang;

View file

@ -512,6 +512,7 @@ void extract_summary_data_from_save(const game_state& state, config& out)
}
out["leader"] = leader;
out["map_data"] = "";
if(!shrouded) {
if(has_snapshot) {

View file

@ -34,9 +34,13 @@
#include <sstream>
namespace {
const config *help_config = NULL;
const config *game_config = NULL;
game_data *game_info = NULL;
// The default toplevel.
help::section toplevel;
// All sections and topics not referenced from the default toplevel.
help::section hidden_sections;
config dummy_cfg;
std::vector<std::string> empty_string_vector;
const int max_section_level = 15;
@ -67,6 +71,9 @@ namespace {
if (id.find("weaponspecial_") == 0) {
return false;
}
if (id == "hidden") {
return false;
}
return true;
}
@ -131,15 +138,118 @@ namespace help {
help_manager::help_manager(const config *cfg, game_data *gameinfo) {
game_config = cfg == NULL ? &dummy_cfg : cfg;
game_info = gameinfo;
if (game_config != NULL) {
help_config = game_config->child("help");
const config *help_config = game_config->child("help");
if (help_config == NULL) {
help_config = &dummy_cfg;
}
try {
toplevel = parse_config(help_config);
// Create a config object that contains everything that is
// not referenced from the toplevel element. Read this
// config and save these sections and topics so that they
// can be referenced later on when showing help about
// specified things, but that should not be shown when
// opening the help browser in the default manner.
config hidden_toplevel;
std::stringstream ss;
config::const_child_itors itors;
for (itors = help_config->child_range("section"); itors.first != itors.second;
itors.first++) {
const std::string id = (*(*itors.first))["id"];
if (find_section(toplevel, id) == NULL) {
// This section does not exist referenced from the
// toplevel. Hence, add it to the hidden ones if it
// is not referenced from another section.
if (!section_is_referenced(id, *help_config)) {
if (ss.str() != "") {
ss << ",";
}
ss << id;
}
}
}
hidden_toplevel["sections"] = ss.str();
ss.str("");
for (itors = help_config->child_range("topic"); itors.first != itors.second;
itors.first++) {
const std::string id = (*(*itors.first))["id"];
if (find_topic(toplevel, id) == NULL) {
if (!topic_is_referenced(id, *help_config)) {
if (ss.str() != "") {
ss << ",";
}
ss << id;
}
}
}
hidden_toplevel["topics"] = ss.str();
config hidden_cfg = *help_config;
// Change the toplevel to our new, custom built one.
hidden_cfg.clear_children("toplevel");
hidden_cfg.add_child("toplevel", hidden_toplevel);
hidden_sections = parse_config(&hidden_cfg);
}
catch (parse_error e) {
std::stringstream msg;
msg << "Parse error when parsing help text: '" << e.message << "'";
std::cerr << msg.str() << std::endl;
}
}
game_info = gameinfo;
}
help_manager::~help_manager() {
game_config = NULL;
game_info = NULL;
toplevel = section();
hidden_sections = section();
}
bool section_is_referenced(const std::string &section_id, const config &cfg) {
const config *toplevel = cfg.child("toplevel");
if (toplevel != NULL) {
const std::vector<std::string> toplevel_refs
= config::quoted_split((*toplevel)["sections"]);
if (std::find(toplevel_refs.begin(), toplevel_refs.end(), section_id)
!= toplevel_refs.end()) {
return true;
}
}
for (config::const_child_itors itors = cfg.child_range("section");
itors.first != itors.second; itors.first++) {
const std::vector<std::string> sections_refd
= config::quoted_split((*(*itors.first))["sections"]);
if (std::find(sections_refd.begin(), sections_refd.end(), section_id)
!= sections_refd.end()) {
return true;
}
}
return false;
}
bool topic_is_referenced(const std::string &topic_id, const config &cfg) {
const config *toplevel = cfg.child("toplevel");
if (toplevel != NULL) {
const std::vector<std::string> toplevel_refs
= config::quoted_split((*toplevel)["topics"]);
if (std::find(toplevel_refs.begin(), toplevel_refs.end(), topic_id)
!= toplevel_refs.end()) {
return true;
}
}
for (config::const_child_itors itors = cfg.child_range("section");
itors.first != itors.second; itors.first++) {
const std::vector<std::string> topics_refd
= config::quoted_split((*(*itors.first))["topics"]);
if (std::find(topics_refd.begin(), topics_refd.end(), topic_id)
!= topics_refd.end()) {
return true;
}
}
return false;
}
void parse_config_internal(const config *help_cfg, const config *section_cfg,
section &sec, int level) {
if (level > max_section_level) {
@ -179,7 +289,7 @@ void parse_config_internal(const config *help_cfg, const config *section_cfg,
generate_sections((*section_cfg)["generator"]);
std::transform(generated_sections.begin(), generated_sections.end(),
std::back_inserter(sec.sections), create_section());
const std::vector<std::string> topics = config::quoted_split((*section_cfg)["topics"]);
const std::vector<std::string> topics = config::quoted_split((*section_cfg)["topics"]);
// Find all topics in this section.
for (it = topics.begin(); it != topics.end(); it++) {
config const *topic_cfg = help_cfg->find_child("topic", "id", *it);
@ -205,7 +315,6 @@ void parse_config_internal(const config *help_cfg, const config *section_cfg,
generate_topics((*section_cfg)["generator"]);
std::copy(generated_topics.begin(), generated_topics.end(),
std::back_inserter(sec.topics));
}
}
@ -550,10 +659,6 @@ std::string generate_about_text() {
return text;
}
help_manager::~help_manager() {
help_config = NULL;
}
bool topic::operator==(const topic &t) const {
return t.id == id;
}
@ -581,6 +686,9 @@ section::section(const section &sec)
}
section& section::operator=(const section &sec) {
title = sec.title;
id = sec.id;
std::copy(sec.topics.begin(), sec.topics.end(), std::back_inserter(topics));
std::transform(sec.sections.begin(), sec.sections.end(),
std::back_inserter(sections), create_section());
return *this;
@ -955,10 +1063,20 @@ void help_text_area::set_items(const std::vector<std::string> &parsed_items,
void help_text_area::handle_ref_cfg(const config &cfg) {
const std::string dst = cfg["dst"];
const std::string text = cfg["text"];
const bool force = get_bool(cfg["force"]);
bool show_ref = true;
if (find_topic(toplevel_, dst) == NULL && !force) {
show_ref = false;
}
if (dst == "" || text == "") {
throw parse_error("Ref markup must have both dst and text attributes.");
}
add_text_item(text, dst);
if (show_ref) {
add_text_item(text, dst);
}
else {
add_text_item(text);
}
}
void help_text_area::handle_img_cfg(const config &cfg) {
@ -1329,7 +1447,7 @@ void help_text_area::draw() {
if (dst.y < (int)height() && dst.y + (*it).surf->h > 0) {
dst.x += location().x;
dst.y += location().y;
sdl_safe_blit((*it).surf, NULL, screen, &dst);
SDL_BlitSurface((*it).surf, NULL, screen, &dst);
}
}
update_rect(location());
@ -1431,7 +1549,7 @@ std::string help_text_area::ref_at(const int x, const int y) {
help_browser::help_browser(display &disp, section &toplevel)
help_browser::help_browser(display &disp, const section &toplevel)
: gui::widget(disp), disp_(disp), menu_(disp, toplevel),
text_area_(disp, toplevel), toplevel_(toplevel), ref_cursor_(false),
back_button_(disp, translate_string("help_back"), gui::button::TYPE_PRESS),
@ -1616,6 +1734,21 @@ const topic *find_topic(const section &sec, const std::string &id) {
return NULL;
}
const section *find_section(const section &sec, const std::string &id) {
section_list::const_iterator sit =
std::find_if(sec.sections.begin(), sec.sections.end(), has_id(id));
if (sit != sec.sections.end()) {
return *sit;
}
for (sit = sec.sections.begin(); sit != sec.sections.end(); sit++) {
const section *s = find_section(*(*sit), id);
if (s != NULL) {
return s;
}
}
return NULL;
}
void help_browser::show_topic(const std::string &topic_id) {
const topic *t = find_topic(toplevel_, topic_id);
if (t != NULL) {
@ -1833,6 +1966,41 @@ std::string get_first_word(const std::string &s) {
}
void show_help(display &disp, std::string show_topic, int xloc, int yloc) {
show_help(disp, toplevel, show_topic, xloc, yloc);
}
void show_help(display &disp, const std::vector<std::string> &topics_to_show,
const std::vector<std::string> &sections_to_show, const std::string show_topic,
int xloc, int yloc) {
section to_show;
std::vector<std::string>::const_iterator it;
for (it = topics_to_show.begin(); it != topics_to_show.end(); it++) {
// Check both the visible toplevel and the hidden sections.
const topic *t = find_topic(toplevel, *it);
t = t == NULL ? find_topic(hidden_sections, *it) : t;
if (t != NULL) {
to_show.topics.push_back(*t);
}
else {
std::cerr << "Warning: topic with id " << *it << " does not exist." << std::endl;
}
}
for (it = sections_to_show.begin(); it != sections_to_show.end(); it++) {
const section *s = find_section(toplevel, *it);
s = s == NULL ? find_section(hidden_sections, *it) : s;
if (s != NULL) {
to_show.add_section(*s);
}
else {
std::cerr << "Warning: section with id " << *it << " does not exist." << std::endl;
}
}
show_help(disp, to_show, show_topic, xloc, yloc);
}
/// Open a help dialog using a toplevel other than the default.
void show_help(display &disp, const section &toplevel_sec, const std::string show_topic,
int xloc, int yloc) {
const events::event_context dialog_events_context;
const gui::dialog_manager manager;
const events::resize_lock prevent_resizing;
@ -1861,8 +2029,7 @@ void show_help(display &disp, std::string show_topic, int xloc, int yloc) {
NULL, &buttons_ptr, &restorer);
try {
section toplevel = parse_config(help_config);
help_browser hb(disp, toplevel);
help_browser hb(disp, toplevel_sec);
hb.set_location(xloc + left_padding, yloc + top_padding);
hb.set_width(width - left_padding - right_padding);
hb.set_height(height - top_padding - bot_padding);

View file

@ -83,6 +83,7 @@ public:
has_id(const std::string &id) : id_(id) {}
bool operator()(const topic &t) { return t.id == id_; }
bool operator()(const section &s) { return s.id == id_; }
bool operator()(const section *s) { return s != NULL && s->id == id_; }
private:
const std::string id_;
};
@ -345,7 +346,7 @@ private:
/// A help browser widget.
class help_browser : public gui::widget {
public:
help_browser(display &disp, section &toplevel);
help_browser(display &disp, const section &toplevel);
// Overloaded from widget so that the layout may be adjusted to fit
// the new dimensions.
@ -403,8 +404,6 @@ UNIT_DESCRIPTION_TYPE description_type(const unit_type &type);
std::vector<topic> generate_ability_topics();
std::vector<topic> generate_weapon_special_topics();
/// Parse a help config, return the top level section. Return an empty
/// section if cfg is NULL.
section parse_config(const config *cfg);
@ -412,11 +411,23 @@ section parse_config(const config *cfg);
void parse_config_internal(const config *help_cfg, const config *section_cfg,
section &sec, int level=0);
/// Return true if the section with id section_id is referenced from
/// another section in the config, or the toplevel.
bool section_is_referenced(const std::string &section_id, const config &cfg);
/// Return true if the topic with id topic_id is referenced from
/// another section in the config, or the toplevel.
bool topic_is_referenced(const std::string &topic_id, const config &cfg);
/// Search for the topic with the specified identifier in the section
/// and it's subsections. Return the found topic, or NULL if none could
/// and its subsections. Return the found topic, or NULL if none could
/// be found.
const topic *find_topic(const section &sec, const std::string &id);
/// Search for the section with the specified identifier in the section
/// and its subsections. Return the found section or NULL if none could
/// be found.
const section *find_section(const section &sec, const std::string &id);
/// Parse a text string. Return a vector with the different parts of the
/// text. Each markup item is a separate part while the text between
/// markups are separate parts.
@ -450,8 +461,22 @@ std::string cap(const std::string &s);
/// it.
std::string get_first_word(const std::string &s);
/// Open a help dialog. The help topic will have the topic with id
/// show_topic open if it is not the empty string.
/// Open a help dialog showing the topics with ids topics_to_show and
/// the sections with ids sections_to_show. Subsections and subtopics of
/// the sections will be added recursively according to the help config.
void show_help(display &disp, const std::vector<std::string> &topics_to_show,
const std::vector<std::string> &sections_to_show, const std::string show_topic="",
int xloc=-1, int yloc=-1);
/// Open a help dialog using a toplevel other than the default. This
/// allows for complete customization of the contents, although not in a
/// very easy way.
void show_help(display &disp, const section &toplevel, const std::string show_topic="",
int xloc=-1, int yloc=-1);
/// Open the help browser. The help browser will have the topic with id
/// show_topic open if it is not the empty string. The default topic
/// will be shown if show_topic sis the empty string.
void show_help(display &disp, const std::string show_topic="", int xloc=-1, int yloc=-1);
} // End namespace help.

View file

@ -92,6 +92,7 @@ HOTKEY_COMMAND string_to_command(const std::string& str)
m.insert(val("speaktoally",HOTKEY_SPEAK_ALLY));
m.insert(val("speaktoall",HOTKEY_SPEAK_ALL));
m.insert(val("help",HOTKEY_HELP));
m.insert(val("chatlog",HOTKEY_CHAT_LOG));
}
const std::map<std::string,HOTKEY_COMMAND>::const_iterator i = m.find(str);
@ -490,6 +491,11 @@ void execute_command(display& disp, HOTKEY_COMMAND command, command_executor* ex
executor->show_help();
}
break;
case HOTKEY_CHAT_LOG:
if(executor) {
executor->show_chat_log();
}
break;
case HOTKEY_EDIT_SET_TERRAIN:
if(executor)
executor->edit_set_terrain();

View file

@ -36,6 +36,7 @@ enum HOTKEY_COMMAND { HOTKEY_CYCLE_UNITS, HOTKEY_END_UNIT_TURN, HOTKEY_LEADER,
HOTKEY_LABEL_TERRAIN, HOTKEY_SHOW_ENEMY_MOVES, HOTKEY_BEST_ENEMY_MOVES,
HOTKEY_DELAY_SHROUD, HOTKEY_UPDATE_SHROUD, HOTKEY_CONTINUE_MOVE,
HOTKEY_SEARCH, HOTKEY_SPEAK_ALLY, HOTKEY_SPEAK_ALL, HOTKEY_HELP,
HOTKEY_CHAT_LOG,
//editing specific commands
HOTKEY_EDIT_SET_TERRAIN,
@ -120,6 +121,7 @@ public:
virtual void continue_move() {}
virtual void search() {}
virtual void show_help() {}
virtual void show_chat_log() {}
// Map editor stuff.
virtual void edit_set_terrain() {}

View file

@ -332,7 +332,7 @@ SDL_Surface* get_image(const image::locator& i_locator, TYPE type, COLOUR_ADJUST
const scoped_sdl_surface scoped_surface(result);
result = adjust_surface_colour(scaled_surf,red_adjust,green_adjust,blue_adjust);
} else {
result = clone_surface(scaled_surf);
result = create_optimized_surface(scaled_surf);
}
if(result == NULL) {
@ -518,7 +518,7 @@ SDL_Surface* getMinimap(int w, int h, const gamemap& map,
assert(surf != NULL);
SDL_Rect maprect = {x*scale*3/4,y*scale + (is_odd(x) ? scale/2 : 0),0,0};
sdl_safe_blit(surf, NULL, minimap, &maprect);
SDL_BlitSurface(surf, NULL, minimap, &maprect);
}
}
}

View file

@ -321,7 +321,7 @@ gamemap::TERRAIN gamemap::get_terrain(const gamemap::location& loc) const
TERRAIN used_terrain = 0;
int terrain_count = 0;
for(int i = 0; i != nitems; ++i) {
if(items[i] != used_terrain && !is_village(items[i]) && !is_keep(items[i])) {
if(items[i] != used_terrain && !is_village(items[i]) && !is_keep(items[i]) && !is_castle(items[i])) {
const int c = std::count(items+i+1,items+nitems,items[i]) + 1;
if(c > terrain_count) {
used_terrain = items[i];

View file

@ -168,7 +168,7 @@ void multiplayer_game_setup_dialog::set_area(const SDL_Rect& area)
int height = int(area.h);
const int left = area.x;
const int top = area.y;
const int border_size = 5;
const int border_size = 6;
const int right = left + width;
const int bottom = top + height;
@ -197,7 +197,7 @@ void multiplayer_game_setup_dialog::set_area(const SDL_Rect& area)
SDL_Rect rect;
//the sliders and other options on the right side of the dialog
rect.x = xpos + minimap_width + maps_menu_->width() + border_size*2;
rect.x = xpos + minimap_width + maps_menu_->width() + border_size;
rect.y = ypos;
rect.w = maximum<int>(0,right - border_size - rect.x);
//a font sized "12" isn't necessarily 12 pixel high.
@ -205,38 +205,38 @@ void multiplayer_game_setup_dialog::set_area(const SDL_Rect& area)
turns_restorer_ = surface_restorer(&disp_.video(),rect);
rect.y += rect.h + border_size*2;
rect.y += rect.h + border_size + 1;
turns_slider_->set_location(rect);
turns_slider_->set_dirty();
//Village Gold
rect.y += rect.h + border_size*2;
rect.y += rect.h + border_size + 1;
village_gold_restorer_ = surface_restorer(&disp_.video(),rect);
rect.y += rect.h + border_size*2;
rect.y += rect.h + border_size + 1;
village_gold_slider_->set_location(rect);
village_gold_slider_->set_dirty();
//Experience Modifier
rect.y += rect.h + border_size*2;
rect.y += rect.h + border_size + 1;
xp_restorer_ = surface_restorer(&disp_.video(),rect);
rect.y += rect.h + border_size*2;
rect.y += rect.h + border_size + 1;
xp_modifier_slider_->set_location(rect);
xp_modifier_slider_->set_dirty();
//FOG of war
rect.y += rect.h + border_size*2;
rect.y += rect.h + border_size + 1;
fog_game_->set_location(rect.x,rect.y);
fog_game_->set_dirty();
rect.y += fog_game_->location().h + border_size;
rect.y += fog_game_->location().h + border_size + 1;
//Shroud
shroud_game_->set_location(rect.x,rect.y);
@ -256,11 +256,16 @@ void multiplayer_game_setup_dialog::set_area(const SDL_Rect& area)
rect.y += vision_combo_->height() + border_size;
gui::button* left_button = launch_game_;
gui::button* right_button = cancel_game_;
#ifdef OK_BUTTON_ON_RIGHT
std::swap(left_button,right_button);
#endif
//Buttons
cancel_game_->set_location(right - cancel_game_->width() - gui::ButtonHPadding,
bottom - cancel_game_->height() - gui::ButtonVPadding);
launch_game_->set_location(right - cancel_game_->width() - launch_game_->width() - gui::ButtonHPadding*2,
bottom - launch_game_->height() - gui::ButtonVPadding);
right_button->set_location(right - right_button->width() - gui::ButtonHPadding,bottom - right_button->height() - gui::ButtonVPadding);
left_button->set_location(right - right_button->width() - left_button->width() - gui::ButtonHPadding*2,bottom - left_button->height() - gui::ButtonVPadding);
cancel_game_->set_dirty();
launch_game_->set_dirty();

View file

@ -343,9 +343,16 @@ void mp_connect::set_area(const SDL_Rect& rect)
// Wait to players, Configure players
//gui::draw_dialog_background(left, right, width, height, *disp_, "menu");
gui::button* left_button = &launch_;
gui::button* right_button = &cancel_;
#ifdef OK_BUTTON_ON_RIGHT
std::swap(left_button,right_button);
#endif
//Buttons
cancel_.set_location(right - cancel_.width() - gui::ButtonHPadding,bottom-cancel_.height()-gui::ButtonVPadding);
launch_.set_location(right - cancel_.width() - launch_.width() - gui::ButtonHPadding*2,bottom-launch_.height()-gui::ButtonVPadding);
right_button->set_location(right - right_button->width() - gui::ButtonHPadding,bottom-right_button->height()-gui::ButtonVPadding);
left_button->set_location(right - right_button->width() - left_button->width() - gui::ButtonHPadding*2,bottom-left_button->height()-gui::ButtonVPadding);
ai_.set_location(left+30,bottom-60);
@ -589,10 +596,10 @@ lobby::RESULT mp_connect::process()
side["description"] = preferences::login();
for(size_t m = 0; m != combos_type_.size(); ++m) {
if(m != n) {
if(combos_type_[m].selected() == 4){
combos_type_[m].set_selected(0);
if(combos_type_[m].selected() == 5){
combos_type_[m].set_selected(2);
config& si = **(sides.first+m);
si["controller"] = "network";
si["controller"] = "ai";
si["description"] = "";
}
}

View file

@ -487,7 +487,7 @@ void set_default_send_size(size_t max_size)
default_max_send_size = max_size;
}
void send_data(const config& cfg, connection connection_num, size_t max_size)
void send_data(const config& cfg, connection connection_num, size_t max_size, SEND_TYPE mode)
{
if(cfg.empty()) {
return;
@ -533,7 +533,7 @@ void send_data(const config& cfg, connection connection_num, size_t max_size)
//if the data is less than our maximum chunk, and there is no data queued to send
//to this host, then send all data now
if((max_size == 0 || value.size()+1 <= max_size) && send_queue.count(connection_num) == 0) {
if(mode == SEND_DATA && (max_size == 0 || value.size()+1 <= max_size) && send_queue.count(connection_num) == 0) {
std::cerr << "sending " << (value.size()+1) << " bytes\n";
const int res = SDLNet_TCP_Send(get_socket(connection_num),
const_cast<char*>(value.c_str()),
@ -553,10 +553,17 @@ void send_data(const config& cfg, connection connection_num, size_t max_size)
std::copy(value.begin(),value.end(),itor->second.buf.begin());
itor->second.buf.back() = 0;
process_send_queue(connection_num,max_size);
if(mode == SEND_DATA) {
process_send_queue(connection_num,max_size);
}
}
}
void queue_data(const config& cfg, connection connection_num)
{
send_data(cfg,connection_num,0,QUEUE_ONLY);
}
void process_send_queue(connection connection_num, size_t max_size)
{
if(connection_num == 0) {
@ -595,6 +602,8 @@ void process_send_queue(connection connection_num, size_t max_size)
throw error("Sending queued data failed",connection_num);
}
std::cerr << "sent.\n";
upto += bytes_to_send;
//if we've now sent the entire item, erase it from the send queue

View file

@ -74,6 +74,8 @@ connection receive_data(config& cfg, connection connection_num=0, int timeout=0)
//sets the default maximum number of bytes to send to a client at a time
void set_default_send_size(size_t send_size);
enum SEND_TYPE { SEND_DATA, QUEUE_ONLY };
//function to send data down a given connection, or broadcast
//to all peers if connection_num is 0. throws error.
//it will send a maximum of 'max_size' bytes. If cfg when serialized is more than
@ -82,9 +84,15 @@ void set_default_send_size(size_t send_size);
//appended to the send queue, and max_size bytes in the send queue will be sent.
//if 'max_size' is 0, then the entire contents of the send_queue as well as 'cfg'
//will be sent.
//if 'mode' is set to 'QUEUE_ONLY', then no data will be sent at all: only placed
//in the send queue. This will guarantee that this function never throws
//network::error exceptions
//
//data in the send queue can be sent using process_send_queue
void send_data(const config& cfg, connection connection_num=0, size_t max_size=0);
void send_data(const config& cfg, connection connection_num=0, size_t max_size=0, SEND_TYPE mode=SEND_DATA);
//function to queue data to be sent. queue_data(cfg,sock) is equivalent to send_data(cfg,sock,0,QUEUE_ONLY)
void queue_data(const config& cfg, connection connection_num=0);
//function to send any data that is in a connection's send_queue, up to a maximum
//of 'max_size' bytes -- or the entire send queue if 'max_size' bytes is 0

View file

@ -936,6 +936,7 @@ bool turn_info::can_execute_command(hotkey::HOTKEY_COMMAND command) const
case hotkey::HOTKEY_SPEAK:
case hotkey::HOTKEY_SPEAK_ALLY:
case hotkey::HOTKEY_SPEAK_ALL:
case hotkey::HOTKEY_CHAT_LOG:
return network::nconnections() > 0;
case hotkey::HOTKEY_REDO:
@ -1722,10 +1723,12 @@ void turn_info::recall()
<< string_table["xp"] << ": "
<< u->experience() << "/";
if(u->type().advances_to().empty())
if(u->can_advance() == false) {
option << "-";
else
} else {
option << u->max_experience();
}
options.push_back(option.str());
}
@ -1787,7 +1790,6 @@ bool turn_info::has_friends() const
void turn_info::speak()
{
create_textbox(floating_textbox::TEXTBOX_MESSAGE,string_table["message"] + ":", has_friends() ? string_table["speak_allies_only"] : "", preferences::message_private());
}
@ -1885,7 +1887,7 @@ void turn_info::unit_list()
<< "/" << i->second.max_hitpoints() << ","
<< i->second.experience() << "/";
if(i->second.type().advances_to().empty())
if(i->second.can_advance() == false)
row << "-";
else
row << i->second.max_experience();
@ -2027,6 +2029,12 @@ void turn_info::show_help()
help::show_help(gui_);
}
void turn_info::show_chat_log()
{
std::string text = recorder.build_chat_log(teams_[gui_.viewing_team()].team_name());
gui::show_dialog(gui_,NULL,string_table["chat_log"],"",gui::CLOSE_ONLY,NULL,NULL,"",&text);
}
void turn_info::do_search(const std::string& new_search)
{
if(new_search.empty() == false && new_search != last_search_)

View file

@ -152,6 +152,7 @@ private:
virtual void continue_move();
virtual void search();
virtual void show_help();
virtual void show_chat_log();
virtual hotkey::ACTION_STATE get_action_state(hotkey::HOTKEY_COMMAND command) const;
void do_search(const std::string& str);

View file

@ -376,6 +376,30 @@ void replay::speak(const config& cfg)
}
}
std::string replay::build_chat_log(const std::string& team) const
{
std::stringstream str;
const config::child_list& cmd = commands();
for(config::child_list::const_iterator i = cmd.begin(); i != cmd.end(); ++i) {
const config* speak = (**i).child("speak");
if(speak != NULL) {
const config& cfg = *speak;
const std::string& team_name = cfg["team_name"];
if(team_name == "" || team_name == team) {
if(team_name == "") {
str << "<" << cfg["description"] << "> ";
} else {
str << "*" << cfg["description"] << "* ";
}
str << cfg["message"] << "\n";
}
}
}
return str.str();
}
config replay::get_data_range(int cmd_start, int cmd_end, DATA_TYPE data_type)
{
log_scope("get_data_range\n");
@ -844,13 +868,11 @@ bool do_replay(display& disp, const gamemap& map, const game_data& gameinfo,
u = units.find(src);
tgt = units.find(dst);
if(u != units.end() && u->second.advances() &&
u->second.type().advances_to().empty() == false) {
if(u != units.end() && u->second.advances()) {
advancing_units.push_back(u->first);
}
if(tgt != units.end() && tgt->second.advances() &&
tgt->second.type().advances_to().empty() == false) {
if(tgt != units.end() && tgt->second.advances()) {
advancing_units.push_back(tgt->first);
}

View file

@ -56,6 +56,7 @@ public:
void end_turn();
void speak(const config& cfg);
std::string build_chat_log(const std::string& team) const;
//get data range will get a range of moves from the replay system.
//if data_type is 'ALL_DATA' then it will return all data in this range

View file

@ -153,7 +153,7 @@ report generate_report(TYPE type, const gamemap& map, const unit_map& units,
break;
case UNIT_XP:
if(u->second.type().advances_to().empty()) {
if(u->second.can_advance() == false) {
str << u->second.experience() << "/-";
} else {
//if killing a unit of the same level as us lets us advance, display in 'good' colour

View file

@ -59,7 +59,6 @@ SDL_Surface* make_neutral_surface(SDL_Surface* surf)
}
SDL_Surface* const result = SDL_ConvertSurface(surf,&get_neutral_pixel_format(),SDL_SWSURFACE);
invalidate_sdl_surface_cache(surf);
if(result != NULL) {
SDL_SetAlpha(result,SDL_SRCALPHA,SDL_ALPHA_OPAQUE);
}
@ -75,13 +74,12 @@ int sdl_add_ref(SDL_Surface* surface)
return 0;
}
SDL_Surface* clone_surface(SDL_Surface* surface)
SDL_Surface* create_optimized_surface(SDL_Surface* surface)
{
if(surface == NULL)
return NULL;
SDL_Surface* const result = display_format_alpha(surface);
invalidate_sdl_surface_cache(surface);
if(result == surface) {
std::cerr << "resulting surface is the same as the source!!!\n";
}
@ -135,7 +133,7 @@ SDL_Surface* scale_surface(SDL_Surface* surface, int w, int h)
}
}
return clone_surface(dst);
return create_optimized_surface(dst);
}
SDL_Surface* scale_surface_blended(SDL_Surface* surface, int w, int h)
@ -212,13 +210,13 @@ SDL_Surface* scale_surface_blended(SDL_Surface* surface, int w, int h)
}
}
return clone_surface(dst);
return create_optimized_surface(dst);
}
SDL_Surface* adjust_surface_colour(SDL_Surface* surface, int r, int g, int b)
{
if(r == 0 && g == 0 && b == 0 || surface == NULL)
return clone_surface(surface);
return create_optimized_surface(surface);
scoped_sdl_surface surf(make_neutral_surface(surface));
@ -246,7 +244,7 @@ SDL_Surface* adjust_surface_colour(SDL_Surface* surface, int r, int g, int b)
}
}
return clone_surface(surf);
return create_optimized_surface(surf);
}
SDL_Surface* greyscale_image(SDL_Surface* surface)
@ -286,7 +284,7 @@ SDL_Surface* greyscale_image(SDL_Surface* surface)
}
}
return clone_surface(surf);
return create_optimized_surface(surf);
}
SDL_Surface* brighten_image(SDL_Surface* surface, double amount)
@ -321,7 +319,7 @@ SDL_Surface* brighten_image(SDL_Surface* surface, double amount)
}
}
return clone_surface(surf);
return create_optimized_surface(surf);
}
SDL_Surface* adjust_surface_alpha(SDL_Surface* surface, double amount)
@ -354,7 +352,7 @@ SDL_Surface* adjust_surface_alpha(SDL_Surface* surface, double amount)
}
}
return clone_surface(surf);
return create_optimized_surface(surf);
}
SDL_Surface* adjust_surface_alpha_add(SDL_Surface* surface, int amount)
@ -387,7 +385,7 @@ SDL_Surface* adjust_surface_alpha_add(SDL_Surface* surface, int amount)
}
}
return clone_surface(surf);
return create_optimized_surface(surf);
}
// Applies a mask on a surface
@ -431,7 +429,7 @@ SDL_Surface* mask_surface(SDL_Surface* surface, SDL_Surface* mask)
}
return surf;
//return clone_surface(surf);
//return create_optimized_surface(surf);
}
// Cuts a rectangle from a surface.
@ -503,7 +501,7 @@ SDL_Surface* blend_surface(SDL_Surface* surface, double amount, Uint32 colour)
}
}
return clone_surface(surf);
return create_optimized_surface(surf);
}
SDL_Surface* flip_surface(SDL_Surface* surface)
@ -532,7 +530,7 @@ SDL_Surface* flip_surface(SDL_Surface* surface)
}
}
return clone_surface(surf);
return create_optimized_surface(surf);
}
SDL_Surface* flop_surface(SDL_Surface* surface)
@ -561,7 +559,7 @@ SDL_Surface* flop_surface(SDL_Surface* surface)
}
}
return clone_surface(surf);
return create_optimized_surface(surf);
}
SDL_Surface* create_compatible_surface(SDL_Surface* surf, int width, int height)
@ -622,7 +620,7 @@ SDL_Surface* get_surface_portion(SDL_Surface* src, SDL_Rect& area)
SDL_Rect dstarea = {0,0,0,0};
sdl_safe_blit(src,&area,dst,&dstarea);
SDL_BlitSurface(src,&area,dst,&dstarea);
return dst;
}
@ -745,7 +743,7 @@ surface_restorer::~surface_restorer()
void surface_restorer::restore()
{
if(surface_ != NULL) {
sdl_safe_blit(surface_,NULL,target_->getSurface(),&rect_);
SDL_BlitSurface(surface_,NULL,target_->getSurface(),&rect_);
update_rect(rect_);
}
}
@ -761,23 +759,4 @@ void surface_restorer::update()
void surface_restorer::cancel()
{
surface_.assign(NULL);
}
//dummy definition of this SDL-private data structure, so that we can clear
//the surface's cache
struct SDL_BlitMap {
SDL_Surface* dst;
};
void invalidate_sdl_surface_cache(SDL_Surface* surf)
{
if(surf->map->dst != get_video_surface()) {
surf->map->dst = NULL;
}
}
void sdl_safe_blit(SDL_Surface* src, SDL_Rect* srcrect, SDL_Surface* dst, SDL_Rect* dstrect)
{
SDL_BlitSurface(src,srcrect,dst,dstrect);
invalidate_sdl_surface_cache(src);
}
}

View file

@ -46,7 +46,7 @@ int sdl_add_ref(SDL_Surface* surface);
typedef util::scoped_resource<SDL_Surface*,free_sdl_surface> scoped_sdl_surface;
SDL_Surface* make_neutral_surface(SDL_Surface* surf);
SDL_Surface* clone_surface(SDL_Surface* surface);
SDL_Surface* create_optimized_surface(SDL_Surface* surface);
SDL_Surface* scale_surface(SDL_Surface* surface, int w, int h);
SDL_Surface* scale_surface_blended(SDL_Surface* surface, int w, int h);
SDL_Surface* adjust_surface_colour(SDL_Surface* surface, int r, int g, int b);
@ -212,14 +212,4 @@ private:
SDL_Rect rect;
};
//SDL 1.2.x has a bug where after a blit, a surface stores the surface it was last
//blitted to. This is a problem, because if the surface is freed, and then a new
//one created in the same memory location, it will think its blitter knows how to
//blit to that surface when it doesn't.
//
//This function will invalidate the cache, to keep the problem from occurring.
void invalidate_sdl_surface_cache(SDL_Surface* surf);
void sdl_safe_blit(SDL_Surface* src, SDL_Rect* srcrect, SDL_Surface* dst, SDL_Rect* dstrect);
#endif

View file

@ -134,7 +134,7 @@ bool game::take_side(network::connection player, const config& cfg)
config& reassign = response.add_child("reassign_side");
reassign["from"] = cfg["side"];
reassign["to"] = new_cfg["side"];
network::send_data(response,player);
network::queue_data(response,player);
}
return res;
@ -147,7 +147,7 @@ bool game::take_side(network::connection player, const config& cfg)
//send host notification of taking this side
if(players_.empty() == false) {
network::send_data(cfg,players_.front());
network::queue_data(cfg,players_.front());
}
return true;
@ -236,7 +236,7 @@ void game::add_player(network::connection player)
//tell this player that the game has started
config cfg;
cfg.add_child("start_game");
network::send_data(cfg,player);
network::queue_data(cfg,player);
}
//if the player is already in the game, don't add them.
@ -249,7 +249,7 @@ void game::add_player(network::connection player)
send_user_list();
//send the player the history of the game to-date
network::send_data(history_,player);
network::queue_data(history_,player);
}
void game::remove_player(network::connection player)
@ -266,7 +266,7 @@ void game::remove_player(network::connection player)
if(players_.empty() == false) {
config drop;
drop["side_drop"] = side->second;
network::send_data(drop,players_.front());
network::queue_data(drop,players_.front());
}
sides_taken_.erase(side->second);
@ -319,7 +319,7 @@ void game::send_data(const config& data, network::connection exclude)
for(std::vector<network::connection>::const_iterator
i = players_.begin(); i != players_.end(); ++i) {
if(*i != exclude && (allow_observers_ || sides_.count(*i) == 1)) {
network::send_data(data,*i);
network::queue_data(data,*i);
}
}
}
@ -354,7 +354,7 @@ void game::send_data_team(const config& data, const std::string& team, network::
{
for(std::vector<network::connection>::const_iterator i = players_.begin(); i != players_.end(); ++i) {
if(*i != exclude && player_on_team(team,*i)) {
network::send_data(data,*i);
network::queue_data(data,*i);
}
}
}

View file

@ -90,14 +90,22 @@ void server::run()
config& gamelist = initial_response_.add_child("gamelist");
old_initial_response_ = initial_response_;
bool sync_scheduled = false;
for(int loop = 0;; ++loop) {
try {
if(sync_scheduled) {
//send all players the information that a player has logged
//out of the system
lobby_players_.send_data(sync_initial_response());
sync_scheduled = false;
}
//make sure we log stats every 5 minutes
if((loop%100) == 0 && last_stats_+5*60 < time(NULL)) {
dump_stats();
}
network::process_send_queue();
network::connection sock = network::accept_connection();
@ -500,9 +508,7 @@ void server::run()
e.disconnect();
}
//send all players the information that a player has logged
//out of the system
lobby_players_.send_data(sync_initial_response());
sync_scheduled = true;
std::cerr << "done closing socket...\n";
}
@ -570,7 +576,7 @@ int main(int argc, char** argv)
try {
server(port).run();
} catch(network::error& e) {
std::cerr << "error starting server: " << e.message << "\n";
std::cerr << "caught network error while server was running. aborting.: " << e.message << "\n";
return -1;
}

View file

@ -185,7 +185,7 @@ SDL_Rect draw_dialog_title(int x, int y, display* disp, const std::string& text)
void draw_dialog(int x, int y, int w, int h, display& disp, const std::string& title,
const std::string* style, std::vector<button*>* buttons,
surface_restorer* restorer)
surface_restorer* restorer, button* help_button)
{
int border_size = 10;
SDL_Rect title_area = {0,0,0,0};
@ -209,9 +209,16 @@ void draw_dialog(int x, int y, int w, int h, display& disp, const std::string& t
buttons_area.w += ButtonHPadding;
}
size_t buttons_width = buttons_area.w;
if(help_button != NULL) {
buttons_width += help_button->width() + ButtonHPadding*2;
buttons_area.y = y + h;
}
const int xpos = x;
const int ypos = y - int(title_area.h);
const int width = maximum<int>(w,maximum<int>(int(title_area.w),int(buttons_area.w)));
const int width = maximum<int>(w,maximum<int>(int(title_area.w),int(buttons_width)));
const int height = title_area.h + buttons_area.h + h;
buttons_area.x += xpos + width;
@ -223,11 +230,19 @@ void draw_dialog(int x, int y, int w, int h, display& disp, const std::string& t
}
if(buttons != NULL) {
#ifdef OK_BUTTON_ON_RIGHT
std::reverse(buttons->begin(),buttons->end());
#endif
for(std::vector<button*>::const_iterator b = buttons->begin(); b != buttons->end(); ++b) {
(**b).set_location(buttons_area.x,buttons_area.y);
buttons_area.x += (**b).width() + ButtonHPadding;
}
}
if(help_button != NULL) {
help_button->set_location(x+ButtonHPadding,buttons_area.y);
}
}
void draw_rectangle(int x, int y, int w, int h, Uint32 colour,SDL_Surface* target)
@ -379,18 +394,23 @@ int show_dialog(display& disp, SDL_Surface* image,
SDL_Rect clipRect = disp.screen_area();
const bool use_textbox = text_widget_text != NULL;
const bool editable_textbox = use_textbox && std::find(text_widget_text->begin(),text_widget_text->end(),'\n') == text_widget_text->end();
static const std::string default_text_string = "";
const unsigned int text_box_width = 350;
textbox text_widget(disp,text_box_width,
use_textbox ? *text_widget_text : default_text_string);
use_textbox ? *text_widget_text : default_text_string, editable_textbox);
int text_widget_width = 0;
int text_widget_height = 0;
if(use_textbox) {
text_widget_width =
font::draw_text(NULL, clipRect, message_font_size,
font::NORMAL_COLOUR, text_widget_label, 0, 0, NULL).w +
text_widget.location().w;
text_widget.set_wrap(!editable_textbox);
const SDL_Rect& area = font::text_area(*text_widget_text,message_font_size);
text_widget.set_width(minimum<size_t>(disp.x()/2,maximum<size_t>(area.w,text_widget.location().w)));
text_widget.set_height(minimum<size_t>(disp.y()/2,maximum<size_t>(area.h,text_widget.location().h)));
text_widget_width = font::text_area(text_widget_label,message_font_size).w + text_widget.location().w;;
text_widget_height = text_widget.location().h + 16;
}
@ -580,19 +600,15 @@ int show_dialog(display& disp, SDL_Surface* image,
buttons_ptr.push_back(&*bt);
}
button help_button(disp,string_table["action_help"]);
if(help_topic.empty() == false) {
buttons_ptr.push_back(&help_button);
}
frame_width += left_preview_pane_width + right_preview_pane_width;
frame_height += above_preview_pane_height;
surface_restorer restorer;
button help_button(disp,string_table["action_help"]);
const std::string& title = image == NULL ? caption : "";
draw_dialog(xframe,yframe,frame_width,frame_height,disp,title,dialog_style,&buttons_ptr,&restorer);
draw_dialog(xframe,yframe,frame_width,frame_height,disp,title,dialog_style,&buttons_ptr,&restorer,help_topic.empty() ? NULL : &help_button);
//calculate the positions of the preview panes to the sides of the dialog
if(preview_panes != NULL) {

View file

@ -71,7 +71,7 @@ SDL_Rect draw_dialog_title(int x, int y, display* disp, const std::string& text)
//to its original state after the dialog is drawn.
void draw_dialog(int x, int y, int w, int h, display& disp, const std::string& title,
const std::string* dialog_style=NULL, std::vector<button*>* buttons=NULL,
surface_restorer* restorer=NULL);
surface_restorer* restorer=NULL, button* help_button=NULL);
class dialog_action
{

View file

@ -27,9 +27,9 @@
#include <sstream>
namespace {
const std::string ModificationTypes[] = { "object", "trait" };
const int NumModificationTypes = sizeof(ModificationTypes)/
sizeof(*ModificationTypes);
const std::string ModificationTypes[] = { "object", "trait", "advance" };
const size_t NumModificationTypes = sizeof(ModificationTypes)/
sizeof(*ModificationTypes);
}
bool compare_unit_values::operator()(const unit& a, const unit& b) const
@ -349,14 +349,12 @@ int unit::max_experience() const
bool unit::get_experience(int xp)
{
experience_ += xp;
if(experience_ > max_experience())
experience_ = max_experience();
return advances();
}
bool unit::advances() const
{
return experience_ >= max_experience() && !type().advances_to().empty();
return experience_ >= max_experience() && can_advance();
}
bool unit::gets_hit(int damage)
@ -801,15 +799,24 @@ const std::string& unit::image() const
switch(state_) {
case STATE_NORMAL: return type_->image();
case STATE_DEFENDING_LONG:
return type_->image_defensive(attack_type::LONG_RANGE);
case STATE_DEFENDING_SHORT:
return type_->image_defensive(attack_type::SHORT_RANGE);
case STATE_DEFENDING_SHORT: {
const attack_type::RANGE range = (state_ == STATE_DEFENDING_LONG) ? attack_type::LONG_RANGE : attack_type::SHORT_RANGE;
const unit_animation* const anim = type_->defend_animation(getsHit_,range);
if(anim != NULL) {
const std::string* img = anim->get_frame(attackingMilliseconds_);
if(img != NULL) {
return *img;
}
}
return type_->image_defensive(range);
}
case STATE_ATTACKING: {
if(attackType_ == NULL)
return type_->image();
const std::string* const img =
attackType_->get_frame(attackingMilliseconds_);
attackType_->animation().get_frame(attackingMilliseconds_);
if(img == NULL)
return type_->image_fighting(attackType_->range());
@ -825,10 +832,12 @@ const std::string& unit::image() const
}
}
void unit::set_defending(bool newval, attack_type::RANGE range)
void unit::set_defending(bool newval, bool hits, int ms, attack_type::RANGE range)
{
state_ = newval ? (range == attack_type::LONG_RANGE ? STATE_DEFENDING_LONG :
STATE_DEFENDING_SHORT): STATE_NORMAL;
attackingMilliseconds_ = ms;
getsHit_ = hits;
}
void unit::set_attacking(bool newval, const attack_type* type, int ms)
@ -883,6 +892,37 @@ void unit::set_goto(const gamemap::location& new_goto)
goto_ = new_goto;
}
bool unit::can_advance() const
{
return type().can_advance() || get_modification_advances().empty() == false;
}
config::child_list unit::get_modification_advances() const
{
config::child_list res;
const config::child_list& advances = type().modification_advancements();
for(config::child_list::const_iterator i = advances.begin(); i != advances.end(); ++i) {
if(modification_count("advance",(**i)["id"]) < lexical_cast_default<size_t>((**i)["max_times"],1)) {
res.push_back(*i);
}
}
return res;
}
size_t unit::modification_count(const std::string& type, const std::string& id) const
{
size_t res = 0;
const config::child_list& items = modifications_.get_children(type);
for(config::child_list::const_iterator i = items.begin(); i != items.end(); ++i) {
if((**i)["id"] == id) {
++res;
}
}
return res;
}
void unit::add_modification(const std::string& type,
const config& mod, bool no_add)
{
@ -895,6 +935,15 @@ void unit::add_modification(const std::string& type,
for(config::const_child_itors i = mod.child_range("effect");
i.first != i.second; ++i.first) {
//see if the effect only applies to certain unit types
const std::string& type_filter = (**i.first)["unit_type"];
if(type_filter.empty() == false) {
const std::vector<std::string>& types = config::split(type_filter);
if(std::find(types.begin(),types.end(),this->type().name()) == types.end()) {
continue;
}
}
std::stringstream description;
const std::string& apply_to = (**i.first)["apply_to"];

View file

@ -112,7 +112,7 @@ public:
//(could be in the middle of an attack etc)
const std::string& image() const;
void set_defending(bool newval,
void set_defending(bool newval, bool hits=false, int ms=0,
attack_type::RANGE range=attack_type::LONG_RANGE);
void set_attacking(bool newval, const attack_type* type=NULL, int ms=0);
@ -134,6 +134,11 @@ public:
bool is_flying() const;
bool can_advance() const;
config::child_list get_modification_advances() const;
size_t modification_count(const std::string& type, const std::string& id) const;
void add_modification(const std::string& type, const config& modification,
bool no_add=false);
@ -150,6 +155,7 @@ private:
STATE state_;
const attack_type* attackType_;
int attackingMilliseconds_;
bool getsHit_;
int hitpoints_;
int maxHitpoints_, backupMaxHitpoints_;

View file

@ -203,8 +203,6 @@ bool unit_attack_ranged(display& disp, unit_map& units, const gamemap& map,
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);
const gamemap::location leader_loc = under_leadership(units,a);
unit_map::iterator leader = units.end();
if(leader_loc.valid()) {
@ -215,8 +213,8 @@ bool unit_attack_ranged(display& disp, unit_map& units, const gamemap& map,
//the missile frames are based around the time when the missile impacts.
//the 'real' frames are based around the time when the missile launches.
const int first_missile = minimum<int>(-100,attack.get_first_frame(attack_type::MISSILE_FRAME));
const int last_missile = attack.get_last_frame(attack_type::MISSILE_FRAME);
const int first_missile = minimum<int>(-100,attack.animation().get_first_frame(unit_animation::MISSILE_FRAME));
const int last_missile = attack.animation().get_last_frame(unit_animation::MISSILE_FRAME);
const int real_last_missile = last_missile - first_missile;
const int missile_impact = -first_missile;
@ -224,17 +222,17 @@ bool unit_attack_ranged(display& disp, unit_map& units, const gamemap& map,
const int time_resolution = 20;
const int acceleration = disp.turbo() ? 5:1;
const std::vector<attack_type::sfx>& sounds = attack.sound_effects();
std::vector<attack_type::sfx>::const_iterator sfx_it = sounds.begin();
const std::vector<unit_animation::sfx>& sounds = attack.animation().sound_effects();
std::vector<unit_animation::sfx>::const_iterator sfx_it = sounds.begin();
const std::string& hit_sound = def->second.type().get_hit_sound();
bool played_hit_sound = (hit_sound == "" || hit_sound == "null");
const int play_hit_sound_at = 0;
const bool hits = damage > 0;
const int begin_at = attack.get_first_frame();
const int begin_at = attack.animation().get_first_frame();
const int end_at = maximum((damage+1)*time_resolution+missile_impact,
maximum(attack.get_last_frame(),real_last_missile));
maximum(attack.animation().get_last_frame(),real_last_missile));
const double xsrc = disp.get_location_x(a);
const double ysrc = disp.get_location_y(a);
@ -246,8 +244,7 @@ bool unit_attack_ranged(display& disp, unit_map& units, const gamemap& map,
const bool vflip = b.y > a.y || b.y == a.y && is_even(a.x);
const bool hflip = b.x < a.x;
const attack_type::FRAME_DIRECTION dir =
(a.x == b.x) ? attack_type::VERTICAL:attack_type::DIAGONAL;
const unit_animation::FRAME_DIRECTION dir = (a.x == b.x) ? unit_animation::VERTICAL:unit_animation::DIAGONAL;
bool dead = false;
const int drain_speed = 1*acceleration;
@ -266,6 +263,8 @@ bool unit_attack_ranged(display& disp, unit_map& units, const gamemap& map,
for(int i = begin_at; i < end_at; i += time_resolution*acceleration) {
events::pump();
def->second.set_defending(true,hits,i - missile_impact,attack_type::LONG_RANGE);
//this is a while instead of an if, because there might be multiple
//sounds playing simultaneously or close together
while(!hide && sfx_it != sounds.end() && i >= sfx_it->time) {
@ -284,7 +283,7 @@ bool unit_attack_ranged(display& disp, unit_map& units, const gamemap& map,
const std::string* new_halo = NULL;
int new_halo_x = 0, new_halo_y = 0;
const std::string* unit_image = attack.get_frame(i,NULL,attack_type::UNIT_FRAME,attack_type::VERTICAL,&new_halo,&new_halo_x,&new_halo_y);
const std::string* unit_image = attack.animation().get_frame(i,NULL,unit_animation::UNIT_FRAME,unit_animation::VERTICAL,&new_halo,&new_halo_x,&new_halo_y);
if(att->second.facing_left() == false) {
new_halo_x *= -1;
}
@ -354,8 +353,8 @@ bool unit_attack_ranged(display& disp, unit_map& units, const gamemap& map,
const std::string* new_halo = NULL;
int new_halo_x = 0, new_halo_y = 0;
const std::string* missile_image = attack.get_frame(missile_frame,NULL,
attack_type::MISSILE_FRAME,dir,&new_halo,&new_halo_x,&new_halo_y);
const std::string* missile_image = attack.animation().get_frame(missile_frame,NULL,
unit_animation::MISSILE_FRAME,dir,&new_halo,&new_halo_x,&new_halo_y);
if(att->second.facing_left() == false) {
new_halo_x *= -1;
@ -367,7 +366,7 @@ bool unit_attack_ranged(display& disp, unit_map& units, const gamemap& map,
static const std::string default_missile(game_config::missile_n_image);
static const std::string default_diag_missile(game_config::missile_ne_image);
if(missile_image == NULL) {
if(dir == attack_type::VERTICAL)
if(dir == unit_animation::VERTICAL)
missile_image = &default_missile;
else
missile_image = &default_diag_missile;
@ -523,8 +522,8 @@ bool unit_attack(display& disp, unit_map& units, const gamemap& map,
}
const bool hits = damage > 0;
const std::vector<attack_type::sfx>& sounds = attack.sound_effects();
std::vector<attack_type::sfx>::const_iterator sfx_it = sounds.begin();
const std::vector<unit_animation::sfx>& sounds = attack.animation().sound_effects();
std::vector<unit_animation::sfx>::const_iterator sfx_it = sounds.begin();
const std::string& hit_sound = def->second.type().get_hit_sound();
bool played_hit_sound = (hit_sound == "" || hit_sound == "null");
@ -544,9 +543,9 @@ bool unit_attack(display& disp, unit_map& units, const gamemap& map,
leader->second.set_leading(true);
}
const int begin_at = minimum<int>(-200,attack.get_first_frame());
const int begin_at = minimum<int>(-200,attack.animation().get_first_frame());
const int end_at = maximum<int>((damage+1)*time_resolution,
maximum<int>(200,attack.get_last_frame()));
maximum<int>(200,attack.animation().get_last_frame()));
const double xsrc = disp.get_location_x(a);
const double ysrc = disp.get_location_y(a);
@ -583,6 +582,8 @@ bool unit_attack(display& disp, unit_map& units, const gamemap& map,
for(int i = begin_at; i < end_at; i += time_resolution*acceleration) {
events::pump();
def->second.set_defending(true,hits,i,attack_type::SHORT_RANGE);
//this is a while instead of an if, because there might be multiple
//sounds playing simultaneously or close together
while(!hide && sfx_it != sounds.end() && i >= sfx_it->time) {
@ -627,7 +628,6 @@ bool unit_attack(display& disp, unit_map& units, const gamemap& map,
++flash_num;
}
disp.draw_tile(b.x,b.y,NULL,defender_alpha,defender_colour);
if(leader_loc.valid()) {
disp.draw_tile(leader_loc.x,leader_loc.y);
@ -637,8 +637,8 @@ bool unit_attack(display& disp, unit_map& units, const gamemap& map,
int new_halo_x = 0, new_halo_y = 0;
int xoffset = 0;
const std::string* unit_image = attack.get_frame(i,&xoffset,attack_type::UNIT_FRAME,attack_type::VERTICAL,
&new_halo_image,&new_halo_x,&new_halo_y);
const std::string* unit_image = attack.animation().get_frame(i,&xoffset,unit_animation::UNIT_FRAME,unit_animation::VERTICAL,
&new_halo_image,&new_halo_x,&new_halo_y);
if(!attacker.facing_left()) {
xoffset *= -1;

View file

@ -28,28 +28,8 @@
#include <unistd.h>
#endif
attack_type::attack_type(const config& cfg)
unit_animation::unit_animation(const config& cfg)
{
name_ = cfg["name"];
type_ = cfg["type"];
special_ = cfg["special"];
backstab_ = special_ == "backstab";
icon_ = cfg["icon"];
if(icon_.empty())
icon_ = "attacks/" + name_ + ".png";
range_ = cfg["range"] == "long" ? LONG_RANGE : SHORT_RANGE;
hexes_ = maximum<int>(1,atoi(cfg["hexes"].c_str()));
damage_ = atol(cfg["damage"].c_str());
num_attacks_ = atol(cfg["number"].c_str());
attack_weight_ = atof(cfg["attack_weight"].c_str());
defense_weight_ = atof(cfg["defense_weight"].c_str());
if ( ! attack_weight_ )
attack_weight_ = 1.0;
if ( ! defense_weight_ )
defense_weight_ = 1.0;
config::const_child_itors range = cfg.child_range("frame");
for(; range.first != range.second; ++range.first){
const int beg = atoi((**range.first)["begin"].c_str());
@ -97,6 +77,92 @@ attack_type::attack_type(const config& cfg)
}
}
int unit_animation::get_first_frame(unit_animation::FRAME_TYPE type) const
{
if(frames_[type].empty())
return 0;
else
return minimum<int>(frames_[type].front().start,0);
}
int unit_animation::get_last_frame(unit_animation::FRAME_TYPE type) const
{
if(frames_[type].empty())
return 0;
else
return maximum<int>(frames_[type].back().end,0);
}
const std::string* unit_animation::get_frame(int milliseconds, int* xoff,
unit_animation::FRAME_TYPE type,
unit_animation::FRAME_DIRECTION dir,
const std::string** halo, int* halo_x, int* halo_y) const
{
for(std::vector<frame>::const_iterator i = frames_[type].begin();
i != frames_[type].end(); ++i) {
if(i->start > milliseconds)
return NULL;
if(i->start <= milliseconds && i->end > milliseconds) {
if(xoff != NULL) {
*xoff = i->xoffset;
}
if(halo != NULL) {
if(i->halo.empty()) {
*halo = NULL;
} else {
*halo = &i->halo;
}
if(halo_x != NULL) {
*halo_x = i->halo_x;
}
if(halo_y != NULL) {
*halo_y = i->halo_y;
}
}
if(dir == DIAGONAL && i->image_diagonal != "") {
return &i->image_diagonal;
} else {
return &i->image;
}
}
}
return NULL;
}
const std::vector<unit_animation::sfx>& unit_animation::sound_effects() const
{
return sfx_;
}
attack_type::attack_type(const config& cfg) : animation_(cfg)
{
name_ = cfg["name"];
type_ = cfg["type"];
special_ = cfg["special"];
backstab_ = special_ == "backstab";
icon_ = cfg["icon"];
if(icon_.empty())
icon_ = "attacks/" + name_ + ".png";
range_ = cfg["range"] == "long" ? LONG_RANGE : SHORT_RANGE;
hexes_ = maximum<int>(1,atoi(cfg["hexes"].c_str()));
damage_ = atol(cfg["damage"].c_str());
num_attacks_ = atol(cfg["number"].c_str());
attack_weight_ = atof(cfg["attack_weight"].c_str());
defense_weight_ = atof(cfg["defense_weight"].c_str());
if ( ! attack_weight_ )
attack_weight_ = 1.0;
if ( ! defense_weight_ )
defense_weight_ = 1.0;
}
const std::string& attack_type::name() const
{
return name_;
@ -152,69 +218,6 @@ bool attack_type::backstab() const
return backstab_;
}
int attack_type::get_first_frame(attack_type::FRAME_TYPE type) const
{
if(frames_[type].empty())
return 0;
else
return minimum<int>(frames_[type].front().start,0);
}
int attack_type::get_last_frame(attack_type::FRAME_TYPE type) const
{
if(frames_[type].empty())
return 0;
else
return maximum<int>(frames_[type].back().end,0);
}
const std::string* attack_type::get_frame(int milliseconds, int* xoff,
attack_type::FRAME_TYPE type,
attack_type::FRAME_DIRECTION dir,
const std::string** halo, int* halo_x, int* halo_y) const
{
for(std::vector<frame>::const_iterator i = frames_[type].begin();
i != frames_[type].end(); ++i) {
if(i->start > milliseconds)
return NULL;
if(i->start <= milliseconds && i->end > milliseconds) {
if(xoff != NULL) {
*xoff = i->xoffset;
}
if(halo != NULL) {
if(i->halo.empty()) {
*halo = NULL;
} else {
*halo = &i->halo;
}
if(halo_x != NULL) {
*halo_x = i->halo_x;
}
if(halo_y != NULL) {
*halo_y = i->halo_y;
}
}
if(dir == DIAGONAL && i->image_diagonal != "") {
return &i->image_diagonal;
} else {
return &i->image;
}
}
}
return NULL;
}
const std::vector<attack_type::sfx>& attack_type::sound_effects() const
{
return sfx_;
}
bool attack_type::matches_filter(const config& cfg) const
{
const std::string& filter_range = cfg["range"];
@ -549,6 +552,11 @@ unit_type::unit_type(const config& cfg, const movement_type_map& mv_types,
}
can_advance_ = advances_to().empty() == false;
const config::child_list& defends = cfg_.get_children("defend");
for(config::child_list::const_iterator d = defends.begin(); d != defends.end(); ++d) {
defensive_animations_.push_back(defensive_animation(**d));
}
}
int unit_type::num_traits() const { return race_->num_traits(); }
@ -868,6 +876,39 @@ const std::string& unit_type::race() const
return race_->name();
}
unit_type::defensive_animation::defensive_animation(const config& cfg) : hits(HIT_OR_MISS), range(SHORT_OR_LONG), animation(cfg)
{
const std::string& hits_str = cfg["hits"];
if(hits_str.empty() == false) {
hits = (hits_str == "yes") ? HIT : MISS;
}
const std::string& range_str = cfg["range"];
if(range_str.empty() == false) {
range = (range_str == "short") ? SHORT : LONG;
}
}
bool unit_type::defensive_animation::matches(bool h, attack_type::RANGE r) const
{
if(hits == HIT && h == false || hits == MISS && h == true || range == SHORT && r == attack_type::LONG_RANGE || range == LONG && r == attack_type::SHORT_RANGE) {
return false;
} else {
return true;
}
}
const unit_animation* unit_type::defend_animation(bool hits, attack_type::RANGE range) const
{
for(std::vector<defensive_animation>::const_iterator i = defensive_animations_.begin(); i != defensive_animations_.end(); ++i) {
if(i->matches(hits,range)) {
return &i->animation;
}
}
return NULL;
}
game_data::game_data(const config& cfg)
{
static const std::vector<config*> dummy_traits;

View file

@ -21,26 +21,11 @@
#include <string>
#include <vector>
//the 'attack type' is the type of attack, how many times it strikes,
//and how much damage it does.
class attack_type
//a class to describe a unit's animation sequence
class unit_animation
{
public:
enum RANGE { SHORT_RANGE, LONG_RANGE };
attack_type(const config& cfg);
const std::string& name() const;
const std::string& type() const;
const std::string& special() const;
const std::string& icon() const;
RANGE range() const;
int hexes() const;
int damage() const;
int num_attacks() const;
double attack_weight() const;
double defense_weight() const;
bool backstab() const;
unit_animation(const config& cfg);
enum FRAME_TYPE { UNIT_FRAME, MISSILE_FRAME };
enum FRAME_DIRECTION { VERTICAL, DIAGONAL };
@ -64,24 +49,7 @@ public:
const std::vector<sfx>& sound_effects() const;
bool matches_filter(const config& cfg) const;
bool apply_modification(const config& cfg,std::string* description);
private:
std::string name_;
std::string type_;
std::string special_;
std::string icon_;
RANGE range_;
int hexes_;
int damage_;
int num_attacks_;
double attack_weight_;
double defense_weight_;
//caches whether the unit can backstab. This is important
//because the AI queries it alot.
bool backstab_;
struct frame {
frame(int i1, int i2, const std::string& img, const std::string& halo, int offset, int halo_x, int halo_y)
: start(i1), end(i2), xoffset(offset), image(img), halo(halo), halo_x(halo_x), halo_y(halo_y)
@ -106,6 +74,49 @@ private:
std::vector<sfx> sfx_;
};
//the 'attack type' is the type of attack, how many times it strikes,
//and how much damage it does.
class attack_type
{
public:
enum RANGE { SHORT_RANGE, LONG_RANGE };
attack_type(const config& cfg);
const std::string& name() const;
const std::string& type() const;
const std::string& special() const;
const std::string& icon() const;
RANGE range() const;
int hexes() const;
int damage() const;
int num_attacks() const;
double attack_weight() const;
double defense_weight() const;
bool backstab() const;
const unit_animation& animation() const { return animation_; }
bool matches_filter(const config& cfg) const;
bool apply_modification(const config& cfg,std::string* description);
private:
unit_animation animation_;
std::string name_;
std::string type_;
std::string special_;
std::string icon_;
RANGE range_;
int hexes_;
int damage_;
int num_attacks_;
double attack_weight_;
double defense_weight_;
//caches whether the unit can backstab. This is important
//because the AI queries it alot.
bool backstab_;
};
class unit_movement_type;
//the 'unit movement type' is the basic size of the unit - flying, small land,
@ -176,6 +187,7 @@ public:
int experience_needed() const;
std::vector<std::string> advances_to() const;
const config::child_list& modification_advancements() const { return cfg_.get_children("advancement"); }
const std::string& usage() const;
struct experience_accelerator {
@ -220,6 +232,8 @@ public:
const std::string& race() const;
const unit_animation* defend_animation(bool hits, attack_type::RANGE range) const;
private:
const config& cfg_;
@ -244,6 +258,18 @@ private:
const std::vector<config*>& possibleTraits_;
unit_race::GENDER gender_;
struct defensive_animation
{
defensive_animation(const config& cfg);
bool matches(bool hits, attack_type::RANGE range) const;
enum { HIT, MISS, HIT_OR_MISS } hits;
enum { SHORT, LONG, SHORT_OR_LONG } range;
unit_animation animation;
};
std::vector<defensive_animation> defensive_animations_;
};
struct game_data

View file

@ -34,7 +34,7 @@ textbox::textbox(display& d, int width, const std::string& text, bool editable)
scrollbar_(d,this),
uparrow_(d,"",gui::button::TYPE_PRESS,"uparrow-button"),
downarrow_(d,"",gui::button::TYPE_PRESS,"downarrow-button"),
scroll_bottom_(false), wrap_(false)
scroll_bottom_(false), wrap_(false), line_height_(0), yscroll_(0)
{
static const SDL_Rect area = d.screen_area();
const int height = font::draw_text(NULL,area,font_size,font::NORMAL_COLOUR,"ABCD",0,0).h;
@ -102,22 +102,6 @@ void textbox::draw()
SDL_Rect src;
// Fills the selected area
if(is_selection()) {
int x = minimum<int>(char_pos_[selstart_], char_pos_[selend_]) - text_pos_ + loc.x;
int w = abs(char_pos_[selstart_] - char_pos_[selend_]);
if(!((x > loc.x + loc.w) || ((x + w) < loc.x))) {
src.x = maximum<int>(x, loc.x);
src.y = loc.y;
src.w = src.x + w > loc.x + loc.w ? loc.x + loc.w - src.x : w;
src.h = loc.h;
Uint32 colour = SDL_MapRGB(disp().video().getSurface()->format, 160, 0, 0);
fill_rect_alpha(src,colour,140,disp().video().getSurface());
}
}
if(text_image_ != NULL) {
src.y = 0;
src.w = minimum<size_t>(loc.w,text_image_->w);
@ -173,6 +157,35 @@ void textbox::draw()
scroll_bottom_ = false;
// Fills the selected area
if(is_selection()) {
const int start = minimum<int>(selstart_,selend_);
const int end = maximum<int>(selstart_,selend_);
int startx = char_x_[start];
int starty = char_y_[start];
const int endx = char_x_[end];
const int endy = char_y_[end];
while(starty <= endy) {
const size_t right = starty == endy ? endx : text_image_->w;
if(right <= size_t(startx)) {
break;
}
SDL_Rect rect = {location().x + startx,location().y + starty - src.y,right - startx,line_height_};
SDL_Rect clip = location();
const clip_rect_setter clipper(disp().video().getSurface(),clip);
Uint32 colour = SDL_MapRGB(disp().video().getSurface()->format, 160, 0, 0);
fill_rect_alpha(rect,colour,140,disp().video().getSurface());
starty += int(line_height_);
startx = 0;
}
}
yscroll_ = src.y;
SDL_BlitSurface(text_image_,&src,disp().video().getSurface(),&dest);
}
@ -246,8 +259,10 @@ void textbox::scroll(int pos)
void textbox::update_text_cache(bool changed)
{
if(changed) {
char_pos_.clear();
char_pos_.push_back(0);
char_x_.clear();
char_y_.clear();
char_x_.push_back(0);
char_y_.push_back(0);
// Re-calculate the position of each glyph. We approximate this by asking the
// width of each substring, but this is a flawed assumption which won't work with
@ -278,17 +293,20 @@ void textbox::update_text_cache(bool changed)
int backup = itor - backup_itor;
itor = backup_itor + 1;
if(backup > 0) {
char_pos_.erase(char_pos_.end()-backup, char_pos_.end());
char_x_.erase(char_x_.end()-backup, char_x_.end());
char_y_.erase(char_y_.end()-backup, char_y_.end());
wrapped_text.erase(wrapped_text.end()-backup, wrapped_text.end());
}
}
backup_itor = text_.end();
wrapped_text.push_back(wchar_t('\n'));
char_pos_.push_back(0);
char_x_.push_back(0);
char_y_.push_back(char_y_.back()+1);
visible_string = "";
} else {
wrapped_text.push_back(*itor);
char_pos_.push_back(w);
char_x_.push_back(w);
char_y_.push_back(char_y_.back() + (char(*itor) == '\n' ? 1 : 0));
++itor;
}
}
@ -300,9 +318,16 @@ void textbox::update_text_cache(bool changed)
text_size_.h = location().h;
text_image_.assign(font::get_rendered_text(s, font_size, font::NORMAL_COLOUR));
//so far we've set char_y_ in terms of the line it's on, now set it in terms of proper y
//co-ordinates, by calculating the height of a line, and multiplying each member of char_y_ by that height
line_height_ = font::get_max_height(font_size);
for(std::vector<int>::iterator i = char_y_.begin(); i != char_y_.end(); ++i) {
*i = *i * line_height_;
}
}
int cursor_x = char_pos_[cursor_];
int cursor_x = char_x_[cursor_];
if(cursor_x - text_pos_ > location().w) {
text_pos_ = cursor_x - location().w;
@ -338,31 +363,9 @@ void textbox::handle_event(const SDL_Event& event)
const size_t beg = minimum<size_t>(size_t(selstart_),size_t(selend_));
const size_t end = maximum<size_t>(size_t(selstart_),size_t(selend_));
std::string selection(end - beg,'x');
std::copy(text_.begin()+beg,text_.begin()+end,selection.begin());
copy_to_clipboard(selection);
return;
}
//if the user presses ctrl+v to paste text into the textbox
if(event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_v && (event.key.keysym.mod&KMOD_CTRL) != 0 && editable() && focus()) {
const size_t beg = minimum<size_t>(size_t(selstart_),size_t(selend_));
const size_t end = maximum<size_t>(size_t(selstart_),size_t(selend_));
if(beg < text_.size() && end <= text_.size() && beg != end) {
text_.erase(text_.begin()+beg,text_.begin()+end);
selstart_ = selend_ = cursor_ = int(beg);
}
const std::string& str = copy_from_clipboard();
wide_string tmp;
tmp.resize(str.size());
std::copy(str.begin(),str.end(),tmp.begin());
text_.insert(text_.begin()+minimum(size_t(cursor_),text_.size()),tmp.begin(),tmp.end());
cursor_ += str.size();
update_text_cache(true);
set_dirty();
wide_string ws = wide_string(text_.begin() + beg, text_.begin() + end);
std::string s = wstring_to_string(ws);
copy_to_clipboard(s);
return;
}
@ -374,7 +377,7 @@ void textbox::handle_event(const SDL_Event& event)
if( (grabmouse_ && (event.type == SDL_MOUSEMOTION)) || (
event.type == SDL_MOUSEBUTTONDOWN && (mousebuttons & SDL_BUTTON(1)) && !
(mousex < location().x || mousex > location().x + location().w ||
(mousex < location().x || mousex > location().x + location().w - (show_scrollbar() ? scrollbar_.get_max_width() : 0) ||
mousey < location().y || mousey > location().y + location().h))) {
const int x = mousex - location().x + text_pos_;
@ -382,12 +385,16 @@ void textbox::handle_event(const SDL_Event& event)
int pos = 0;
int distance = x;
for(int i = 1; i < char_pos_.size(); ++i) {
for(int i = 1; i < int(char_x_.size()); ++i) {
if(yscroll_ + y < char_y_[i]) {
break;
}
// Check individually each distance (if, one day, we support
// RTL languages, char_pos[c] may not be monotonous.)
if(abs(x - char_pos_[i]) < distance) {
// RTL languages, char_x_[c] may not be monotonous.)
if(abs(x - char_x_[i]) < distance && yscroll_ + y < char_y_[i] + line_height_) {
pos = i;
distance = abs(x - char_pos_[i]);
distance = abs(x - char_x_[i]);
}
}
@ -485,13 +492,26 @@ void textbox::handle_event(const SDL_Event& event)
if(character != 0)
std::cerr << "Char: " << character << ", c = " << c << "\n";
if(character >= 32 && character != 127) {
changed = true;
if(is_selection())
erase_selection();
if(event.key.keysym.mod & KMOD_CTRL) {
if(c == SDLK_v) {
changed = true;
if(is_selection())
erase_selection();
text_.insert(text_.begin()+cursor_,character);
++cursor_;
wide_string s = string_to_wstring(copy_from_clipboard());
text_.insert(text_.begin()+cursor_, s.begin(), s.end());
cursor_ += s.size();
}
} else {
if(character >= 32 && character != 127) {
changed = true;
if(is_selection())
erase_selection();
text_.insert(text_.begin()+cursor_,character);
++cursor_;
}
}
}

View file

@ -59,7 +59,7 @@ private:
int text_pos_;
int cursor_pos_;
std::vector<int> char_pos_;
std::vector<int> char_x_, char_y_;
bool editable_;
@ -80,6 +80,8 @@ private:
bool wrap_;
size_t line_height_, yscroll_;
void handle_event(const SDL_Event& event);
void draw_cursor(int pos, display &disp) const;

View file

@ -8,19 +8,19 @@ namespace {
namespace gui {
widget::widget(const widget &o) :
disp_(o.disp_), rect_(o.rect_), focus_(o.focus_), dirty_(o.dirty_), hidden_(false), volatile_(o.volatile_),
disp_(o.disp_), rect_(o.rect_), focus_(o.focus_), dirty_(o.dirty_), needs_restore_(o.needs_restore_), hidden_(false), volatile_(o.volatile_),
help_string_(o.help_string_), help_text_(o.help_text_)
{
bg_backup();
}
widget::widget(display& disp) :
disp_(&disp), rect_(EmptyRect), focus_(true), dirty_(true), hidden_(false), volatile_(false), help_string_(0)
disp_(&disp), rect_(EmptyRect), focus_(true), dirty_(true), needs_restore_(false), hidden_(false), volatile_(false), help_string_(0)
{
}
widget::widget(display& disp, const SDL_Rect& rect) :
disp_(&disp), rect_(EmptyRect), focus_(true), dirty_(true), hidden_(false), volatile_(false), help_string_(0)
disp_(&disp), rect_(EmptyRect), focus_(true), dirty_(true), needs_restore_(false), hidden_(false), volatile_(false), help_string_(0)
{
set_location(rect);
bg_backup();
@ -132,6 +132,9 @@ void widget::set_dirty(bool dirty)
}
dirty_ = dirty;
if(dirty_ == false) {
needs_restore_ = true;
}
}
const bool widget::dirty() const
@ -146,7 +149,14 @@ void widget::bg_backup()
void widget::bg_restore() const
{
restorer_.restore();
if(needs_restore_) {
restorer_.restore();
needs_restore_ = false;
} else {
//this function should be able to be relied upon to update the rectangle,
//so do that even if we don't restore
update_rect(location());
}
}
void widget::handle_event(const SDL_Event& event)

View file

@ -69,6 +69,7 @@ private:
SDL_Rect rect_;
bool focus_; // Should user input be ignored?
bool dirty_; // Does the widget need drawn?
mutable bool needs_restore_; //have we drawn ourselves, so that if moved, we need to restore the background?
bool hidden_;