From bd2866fb61f3fbd28dd461a35031fa4969310988 Mon Sep 17 00:00:00 2001 From: Philippe Plantier Date: Mon, 31 May 2004 22:25:37 +0000 Subject: [PATCH] Replacing the terrain transition code by something entirely in WML. Made forests and hills always overlay terrain on their northern (top) side. [building_rule] tag is now called [terrain_graphics] A few changes in the terrain graphics WML element --- data/built.cfg | 706 ++++++++++++++++-- data/scenario-test.cfg | 2 +- .../Heir_To_The_Throne/Elves_Besieged.cfg | 1 + images/undead-vampirelady-defend.png | Bin 706 -> 714 bytes src/builder.cpp | 305 ++++++-- src/builder.hpp | 37 +- src/display.cpp | 187 ++++- src/display.hpp | 26 +- src/image.cpp | 65 +- src/image.hpp | 3 + src/replay.cpp | 3 +- src/terrain.cpp | 9 +- src/terrain.hpp | 2 +- 13 files changed, 1130 insertions(+), 216 deletions(-) diff --git a/data/built.cfg b/data/built.cfg index cfd96b77f8e..872ee0dd99f 100644 --- a/data/built.cfg +++ b/data/built.cfg @@ -1,85 +1,632 @@ -[building_rule] - map=" -C - C -!KC" - image_background="castle-bg-concave-$R" - image_foreground="castle-fg-concave-$R" - rotations=ne,e,se,sw,w,nw -[/building_rule] -[building_rule] +#define TERRAIN_TYPES +"KCDuWFfmHhVSvtgrRd\/|YwipZcs~ " +#enddef + +#define TERRAIN_BASE_PROBABILITY LETTER IMAGE PROBABILITY +[terrain_graphics] + [tile] + x=0 + y=0 + type="{LETTER}" + [image] + z_index=-99 + name={IMAGE} + [/image] + [/tile] + + probability={PROBABILITY} + no_flag="terrain-{LETTER}" + set_flag="terrain-{LETTER}" +[/terrain_graphics] +#enddef + +#define TERRAIN_BASE LETTER IMAGE +{TERRAIN_BASE_PROBABILITY ({LETTER}) {IMAGE} 100} +#enddef + +#define TERRAIN_ADJACENT_4 LETTERS IMAGE +[terrain_graphics] + + map=" + 2 +. 3 + 1 +. 4 + 5 +" + [tile] + pos=1 + type=!{LETTERS} + + [no_flag] + name=transition-@R0 + [/no_flag] + [no_flag] + name=transition-@R1 + [/no_flag] + [no_flag] + name=transition-@R2 + [/no_flag] + [no_flag] + name=transition-@R3 + [/no_flag] + [set_flag] + name=transition-@R0 + [/set_flag] + [set_flag] + name=transition-@R1 + [/set_flag] + [set_flag] + name=transition-@R2 + [/set_flag] + [set_flag] + name=transition-@R3 + [/set_flag] + + [image] + z_index=-98 + name={IMAGE}-@R0-@R1-@R2-@R3 + [/image] + [/tile] + [tile] + pos=2 + type={LETTERS} + no_flag=transition-@R3 + set_flag=transition-@R3 + [/tile] + [tile] + pos=3 + type={LETTERS} + no_flag=transition-@R4 + set_flag=transition-@R4 + [/tile] + [tile] + pos=4 + type={LETTERS} + no_flag=transition-@R5 + set_flag=transition-@R5 + [/tile] + [tile] + pos=5 + type={LETTERS} + no_flag=transition-@R0 + set_flag=transition-@R0 + [/tile] + + rotations=n,ne,se,s,sw,nw +[/terrain_graphics] +#enddef + +#define TERRAIN_ADJACENT_3 LETTERS IMAGE +[terrain_graphics] + map=" + 2 +. 3 + 1 +. 4 + . +" + [tile] + pos=1 + type=!{LETTERS} + + [no_flag] + name=transition-@R0 + [/no_flag] + [no_flag] + name=transition-@R1 + [/no_flag] + [no_flag] + name=transition-@R2 + [/no_flag] + [set_flag] + name=transition-@R0 + [/set_flag] + [set_flag] + name=transition-@R1 + [/set_flag] + [set_flag] + name=transition-@R2 + [/set_flag] + + [image] + z_index=-98 + name={IMAGE}-@R0-@R1-@R2 + [/image] + [/tile] + [tile] + pos=2 + type={LETTERS} + no_flag=transition-@R3 + set_flag=transition-@R3 + [/tile] + [tile] + pos=3 + type={LETTERS} + no_flag=transition-@R4 + set_flag=transition-@R4 + [/tile] + [tile] + pos=4 + type={LETTERS} + no_flag=transition-@R5 + set_flag=transition-@R5 + [/tile] + + rotations=n,ne,se,s,sw,nw +[/terrain_graphics] +#enddef + +#define TERRAIN_ADJACENT_2 LETTERS IMAGE +[terrain_graphics] + map=" + 2 +. 3 + 1 +. . + . +" + [tile] + pos=1 + type=!{LETTERS} + + [no_flag] + name=transition-@R0 + [/no_flag] + [no_flag] + name=transition-@R1 + [/no_flag] + [set_flag] + name=transition-@R0 + [/set_flag] + [set_flag] + name=transition-@R1 + [/set_flag] + + [image] + z_index=-98 + name={IMAGE}-@R0-@R1 + [/image] + [/tile] + [tile] + pos=2 + type={LETTERS} + no_flag=transition-@R3 + set_flag=transition-@R3 + [/tile] + [tile] + pos=3 + type={LETTERS} + no_flag=transition-@R4 + set_flag=transition-@R4 + [/tile] + + rotations=n,ne,se,s,sw,nw +[/terrain_graphics] +#enddef + +#define TERRAIN_ADJACENT_1 LETTERS IMAGE +[terrain_graphics] + + map=" + 2 +. . + 1 +. . + . +" + [tile] + pos=1 + type=!{LETTERS} + + [no_flag] + name=transition-@R0 + [/no_flag] + [set_flag] + name=transition-@R0 + [/set_flag] + + [image] + z_index=-98 + name={IMAGE}-@R0 + [/image] + [/tile] + [tile] + pos=2 + type={LETTERS} + no_flag=transition-@R3 + set_flag=transition-@R3 + [/tile] + + rotations=n,ne,se,s,sw,nw +[/terrain_graphics] +#enddef + +#define TERRAIN_ADJACENT_1234 LETTERS IMAGE +{TERRAIN_ADJACENT_4 ({LETTERS}) {IMAGE}} +{TERRAIN_ADJACENT_3 ({LETTERS}) {IMAGE}} +{TERRAIN_ADJACENT_2 ({LETTERS}) {IMAGE}} +{TERRAIN_ADJACENT_1 ({LETTERS}) {IMAGE}} +#enddef + +#define TERRAIN_ADJACENT_123 LETTERS IMAGE +{TERRAIN_ADJACENT_3 ({LETTERS}) {IMAGE}} +{TERRAIN_ADJACENT_2 ({LETTERS}) {IMAGE}} +{TERRAIN_ADJACENT_1 ({LETTERS}) {IMAGE}} +#enddef + +#define TERRAIN_ADJACENT_12 LETTERS IMAGE +{TERRAIN_ADJACENT_2 ({LETTERS}) {IMAGE}} +{TERRAIN_ADJACENT_1 ({LETTERS}) {IMAGE}} +#enddef + +#define TERRAIN_ADJACENT_NORTH LETTERS IMAGE +[terrain_graphics] + map=" + 2 +. . + 1 +" + [tile] + pos=2 + type=!{LETTERS} + no_flag=transition-s + set_flag=transition-s + [image] + z_index=-99 + name={IMAGE}-s + [/image] + [/tile] + [tile] + no_flag=transition-n + set_flag=transition-n + pos=1 + type={LETTERS} + [/tile] +[/terrain_graphics] + +[terrain_graphics] + map=" + . +2 . + 1 +" + [tile] + pos=2 + type=!{LETTERS} + no_flag=transition-se + set_flag=transition-se + [image] + z_index=-99 + name={IMAGE}-se + [/image] + [/tile] + [tile] + no_flag=transition-nw + set_flag=transition-nw + pos=1 + type={LETTERS} + [/tile] +[/terrain_graphics] + +[terrain_graphics] + map=" + . +. 2 + 1 +" + [tile] + pos=2 + type=!{LETTERS} + no_flag=transition-sw + set_flag=transition-sw + [image] + z_index=-99 + name={IMAGE}-sw + [/image] + [/tile] + [tile] + no_flag=transition-ne + set_flag=transition-ne + pos=1 + type={LETTERS} + [/tile] +[/terrain_graphics] +#enddef + +#define DISABLE_TRANSITIONS LETTER +[terrain_graphics] + map=" + 1 +6 2 + 7 +5 3 + 4 +" + [tile] + pos=1 + set_flag=transition-s + [/tile] + [tile] + pos=2 + set_flag=transition-sw + [/tile] + [tile] + pos=3 + set_flag=transition-nw + [/tile] + [tile] + pos=4 + set_flag=transition-n + [/tile] + [tile] + pos=5 + set_flag=transition-ne + [/tile] + [tile] + pos=6 + set_flag=transition-se + [/tile] + [tile] + pos=7 + type={LETTER} + [/tile] +[/terrain_graphics] +#enddef + +#define CASTLE_WALLS CASTLE NOTCASTLE IMAGE +{DISABLE_TRANSITIONS {CASTLE}} + +[terrain_graphics] + map=" +2 + 2 +1" + [tile] + pos=1 + type={NOTCASTLE} + [/tile] + [tile] + pos=2 + type={CASTLE} + [/tile] + + [image] + z_index=-1 + name="{IMAGE}-bg-concave-@R0" + [/image] + [image] + z_index=1 + name="{IMAGE}-fg-concave-@R0" + [/image] + rotations=ne,e,se,sw,w,nw +[/terrain_graphics] + +[terrain_graphics] map=" 1 1 -C" - +2" [tile] pos=1 - type=!KC + type={NOTCASTLE} + [/tile] + [tile] + pos=2 + type={CASTLE} [/tile] - image_background="castle-bg-convex-$R" - image_foreground="castle-fg-convex-$R" - rotations=ne,e,se,sw,w,nw -[/building_rule] -[building_rule] + [image] + z_index=-1 + name="{IMAGE}-bg-convex-@R0" + [/image] + [image] + z_index=1 + name="{IMAGE}-fg-convex-@R0" + [/image] + rotations=ne,e,se,sw,w,nw +[/terrain_graphics] +#enddef + +#define CASTLE_AND_KEEP CASTLE KEEP CASTLE_IMAGE KEEP_IMAGE +{CASTLE_WALLS {CASTLE} !{CASTLE}{KEEP} {CASTLE_IMAGE}} +{DISABLE_TRANSITIONS {KEEP}} + +[terrain_graphics] map=" -C - C +2 + 2 1" [tile] - # Using anchors for demonstrations's sake pos=1 - type=K + type={KEEP} [/tile] - - image_background="keep-bg-inside-$R" - image_foreground="keep-fg-inside-$R" - rotations=ne,e,se,sw,w,nw -[/building_rule] - -[building_rule] - map=" -!KC - -K" [tile] - # Using [tile] element just for demonstration's sake - x=1 - y=0 - type=!KC + pos=2 + type={CASTLE} [/tile] - image_background="keep-bg-wall-$R" - image_foreground="keep-fg-wall-$R" - rotations=ne,e,se,sw,w,nw -[/building_rule] -[building_rule] + [image] + z_index=-1 + name="{KEEP_IMAGE}-bg-inside-@R0" + [/image] + [image] + z_index=1 + name="{KEEP_IMAGE}-fg-inside-@R0" + [/image] + rotations=ne,e,se,sw,w,nw +[/terrain_graphics] + +[terrain_graphics] map=" -C - !KC -K" +3 + 3 +1" + [tile] + pos=1 + type={KEEP} + [/tile] + [tile] + pos=3 + type=!{CASTLE}{KEEP} + [/tile] - image_background="keep-bg-wall-0-$R" - image_foreground="keep-fg-wall-0-$R" + [image] + z_index=-1 + name="{KEEP_IMAGE}-bg-wall-@R0" + [/image] + [image] + z_index=1 + name="{KEEP_IMAGE}-fg-wall-@R0" + [/image] rotations=ne,e,se,sw,w,nw -[/building_rule] +[/terrain_graphics] -[building_rule] +[terrain_graphics] map=" -!KC - C -K" +2 + 3 +1" - image_background="keep-bg-wall-1-$R" - image_foreground="keep-fg-wall-1-$R" + [tile] + pos=1 + type={KEEP} + [/tile] + [tile] + pos=2 + type={CASTLE} + [/tile] + [tile] + pos=3 + type=!{CASTLE}{KEEP} + [/tile] + + [image] + z_index=-1 + name="{KEEP_IMAGE}-bg-wall-0-@R0" + [/image] + [image] + z_index=1 + name="{KEEP_IMAGE}-fg-wall-0-@R0" + [/image] rotations=ne,e,se,sw,w,nw -[/building_rule] +[/terrain_graphics] + +[terrain_graphics] + map=" +3 + 2 +1" + + [tile] + pos=1 + type={KEEP} + [/tile] + [tile] + pos=2 + type={CASTLE} + [/tile] + [tile] + pos=3 + type=!{CASTLE}{KEEP} + [/tile] + [image] + z_index=-1 + name="{KEEP_IMAGE}-bg-wall-1-@R0" + [/image] + [image] + z_index=1 + name="{KEEP_IMAGE}-fg-wall-1-@R0" + [/image] + rotations=ne,e,se,sw,w,nw +[/terrain_graphics] +#enddef + +# +# Attachs graphics to each known terrain types +# + +{TERRAIN_BASE K keep} +{TERRAIN_BASE C castle} +{TERRAIN_BASE D flag-cave-neutral} +{TERRAIN_BASE u cave} +{TERRAIN_BASE W cavewall} +{TERRAIN_BASE F snow-forest} +{TERRAIN_BASE f forest} +{TERRAIN_BASE m mountains} +{TERRAIN_BASE H snow-hills} +{TERRAIN_BASE_PROBABILITY h hills-variation1 15} +{TERRAIN_BASE_PROBABILITY h hills-variation2 15} +{TERRAIN_BASE_PROBABILITY h hills-variation3 30} +{TERRAIN_BASE h hills} +{TERRAIN_BASE_PROBABILITY S snow2 30} +{TERRAIN_BASE_PROBABILITY S snow3 30} +{TERRAIN_BASE S snow} +{TERRAIN_BASE V flag-snow-neutral} +{TERRAIN_BASE v human-village} +{TERRAIN_BASE t flag-neutral} +{TERRAIN_BASE_PROBABILITY g grassland-rocks 4} +{TERRAIN_BASE_PROBABILITY g grassland-flowers 8} +{TERRAIN_BASE g grassland} +{TERRAIN_BASE r dirt} +{TERRAIN_BASE R road} +{TERRAIN_BASE_PROBABILITY d desert-plant 10} +{TERRAIN_BASE d desert} +{TERRAIN_BASE \ bridge-se-nw} +{TERRAIN_BASE / bridge-ne-sw} +{TERRAIN_BASE | bridge-n-s} +{TERRAIN_BASE Y flag-swampwater-neutral} +{TERRAIN_BASE_PROBABILITY w swampwater2 30} +{TERRAIN_BASE_PROBABILITY w swampwater3 30} +{TERRAIN_BASE w swampwater} +{TERRAIN_BASE i ice} +{TERRAIN_BASE p pier} +{TERRAIN_BASE c coast} +{TERRAIN_BASE s ocean} +{TERRAIN_BASE Z flag-coast-neutral} +{TERRAIN_BASE ~ fog} +{TERRAIN_BASE ( ) void} + +# +# Transition between terrains +# + +# Special transitions go first + +# Castle and keeps +{CASTLE_AND_KEEP C K castle keep} + +# Forest, hills and mountains should always overlay on northern sides +{TERRAIN_ADJACENT_NORTH m mountains} +{TERRAIN_ADJACENT_NORTH H snow-hills} +{TERRAIN_ADJACENT_NORTH h hills} +{TERRAIN_ADJACENT_NORTH F snow-forest} +{TERRAIN_ADJACENT_NORTH f forest} + +# Then, standard transitions +{TERRAIN_ADJACENT_1234 uD cave} +{TERRAIN_ADJACENT_1 F snow-forest} +{TERRAIN_ADJACENT_1 f forest} +{TERRAIN_ADJACENT_1 m mountains} +{TERRAIN_ADJACENT_12 H snow-hills} +{TERRAIN_ADJACENT_12 h hills} +{TERRAIN_ADJACENT_1234 SV snow} +{TERRAIN_ADJACENT_1234 tvg grassland} +{TERRAIN_ADJACENT_1 r dirt} +{TERRAIN_ADJACENT_1 R road} # Graphics do not seem to be here +{TERRAIN_ADJACENT_1 d desert} +{TERRAIN_ADJACENT_1 Yw swampwater} +{TERRAIN_ADJACENT_1 i ice} +{TERRAIN_ADJACENT_1 cZp\|/ coast} +{TERRAIN_ADJACENT_1 s ocean} +{TERRAIN_ADJACENT_1234 ~ fog} +{TERRAIN_ADJACENT_1234 ( ) void} + # Some test cases -#[building_rule] +#[terrain_graphics] # map=" #. 1 # . @@ -98,24 +645,51 @@ K" # set_flag="built-m" # # image_background="mountains-test" -#[/building_rule] -# -#[building_rule] +#[/terrain_graphics] + +#[terrain_graphics] # [tile] # x=0 # y=0 # type=m +# [image] +# z_index=-1 +# name="mountains-test-2" +# [/image] # [/tile] -# probability=20 +# # probability=20 # no_flag="built-m" # set_flag="built-m" -# image_background="mountains-test-2" -#[/building_rule] +# # image_background="mountains-test-2" +# +# precedence=2 +#[/terrain_graphics] # # +#[terrain_graphics] +# terrains=mgcw +# +# [tile] +# x=0 +# y=0 +# type="@" +# [/tile] +# [tile] +# x=1 +# y=1 +# type="po@ual" +# [/tile] +# +# no_flag="built-@T" +# set_flag="built-@T" +# +# precedence=3 +#[/terrain_graphics] + + # A stupid test case, just to demonstrate the has_flag condition -#[building_rule] +#[terrain_graphics] # # [tile] # x=0 @@ -124,9 +698,9 @@ K" # set_flag=moo # [/tile] # -#[/building_rule] +#[/terrain_graphics] # -#[building_rule] +#[terrain_graphics] # [tile] # x=0 # y=0 @@ -139,4 +713,4 @@ K" # has_flag="moo" # [/tile] # image_background=schmurgle -#[/building_rule] +#[/terrain_graphics] diff --git a/data/scenario-test.cfg b/data/scenario-test.cfg index 73f55777f53..96579745744 100644 --- a/data/scenario-test.cfg +++ b/data/scenario-test.cfg @@ -117,5 +117,5 @@ ggggggggggggggggggggggggggggggggggggg letter=C [/terrain] [/event] - [/test] + diff --git a/data/scenarios/Heir_To_The_Throne/Elves_Besieged.cfg b/data/scenarios/Heir_To_The_Throne/Elves_Besieged.cfg index 672e8d58845..c1157fbde18 100644 --- a/data/scenarios/Heir_To_The_Throne/Elves_Besieged.cfg +++ b/data/scenarios/Heir_To_The_Throne/Elves_Besieged.cfg @@ -443,4 +443,5 @@ recruitment_ignore_bad_combat=yes message="There can be no looking back. We must go quickly!" [/message] [/event] + [/scenario] diff --git a/images/undead-vampirelady-defend.png b/images/undead-vampirelady-defend.png index 6f57a32da0cce9b20b57007bf2c201a99edbab6e..b9f20a001d52b5fc92290f29e3d0d4cf93355221 100644 GIT binary patch delta 641 zcmV-{0)G9%1)gU@SZshJvv74Wd0qgal)gv@kGNH@71&0ETz) zzAM5hESwS;OdR8IO(FH-7GIlaF2V!Hcvo@I`?2A$D*y$q0lf9)aeHyNSA}DG0SuOI zUV%8c##GVG6;`KF!R3C3uH$!qx(ou4{54XF-BleJK=5OB|9EuJ*BiU0)vSuuX^=7i z@qK^2y|*H4P~4UxT>zMkV-gkCvGTak-)3~hWA2zFy(>xua^X76%kC63SR~o3V&~+Xrh9d zxyg-+a-sw82_PX;Ddobs@Xnct5|EI^*UOgRc^AtJ;=PNH9CrPh$L0~2Ye|wMNs=T< b`hWcZQM!b4scQAQ00000NkvXXu0mjfPSYTk delta 633 zcmV-<0*3v{1;Pc8E(S6p6nr&Mku)lQPf0{URCwC$nZHT{VGzU*L=b!dJHf(Af{iwU zm0&N}ND3>PlomF5hG;3?3#9Z>EPa%8XZHB!m|MRjAXd9Gu;g-=3*3*{`TktfNRlK; zk|arzBuSDaNs=TJ{4 zC4jVJN7lmwETL{Or%8QiAzft$H8^1Fd7nE`)P|!GjwJ0|YR33^*x+7nx!Z z0Ef%kDjgU=foqU0%gf{L;&6{0lLrpF1$A|EJ91Cji5};RK{3aa)~N!@1ZjA11A@Rs zOSzmGGAa6`uXhQ+Sgt%C9gIeQC|uhCrwi#8%wenm=KKD71PX34kZ36^9iq*1hFrlh zXNv)`vXKerylY(M#1I}3pS3(e0S;W_uZL?P1T5UZnPP6iT!x2ib{6gl)kf?NYbUf6 z%4ZDEc`&5IW#ph(8&upffPqhd@rBVWnqz(eVkiuT!nbh%IJ{%Z9^N2-So<&-d@pcP zYUB`xLphTZ439#9r0nebKCO8J0nT07w!&SwF1#v4+8S%5WDLtCGbVeGGKwyu_8@G)k;uC3Zqv+^II zG@%D3E4_MeA~)gWfzc;;aeN7r|X&*5bx{yC}qd5<=V9TR+1!1k|arzq<_^9X=X>& TAL8^Y00000NkvXXu0mjfgG?O9 diff --git a/src/builder.cpp b/src/builder.cpp index 47d20c569ec..4819ebec612 100644 --- a/src/builder.cpp +++ b/src/builder.cpp @@ -56,6 +56,7 @@ terrain_builder::terrain_builder(const config& cfg, const gamemap& gmap) : { parse_config(cfg); build_terrains(); + //rebuild_terrain(gamemap::location(0,0)); } const std::vector *terrain_builder::get_terrain_at(const gamemap::location &loc, @@ -108,25 +109,64 @@ terrain_builder::terrain_constraint terrain_builder::rotate(const terrain_builde return ret; } -void terrain_builder::replace_rotation(std::string &s, const std::string &replacement) +void terrain_builder::replace_token(std::string &s, const std::string &token, const std::string &replacement) { int pos; - while((pos = s.find("$R")) != std::string::npos) { - s.replace(pos, 2, replacement); + if(token.empty()) { + std::cerr << "Error: empty token in replace_token\n"; + return; + } + while((pos = s.find(token)) != std::string::npos) { + s.replace(pos, token.size(), replacement); } } +void terrain_builder::replace_token(terrain_builder::imagelist &list, const std::string &token, const std::string &replacement) +{ + for(imagelist::iterator itor = list.begin(); itor != list.end(); ++itor) { + replace_token(itor->second, token, replacement); + replace_token(itor->second, token, replacement); + } +} + +void terrain_builder::replace_token(terrain_builder::building_rule &rule, const std::string &token, const std::string& replacement) +{ + constraint_set::iterator cons; + + for(cons = rule.constraints.begin(); cons != rule.constraints.end(); ++cons) { + //Transforms attributes + std::vector::iterator flag; + + for(flag = cons->second.set_flag.begin(); flag != cons->second.set_flag.end(); flag++) { + replace_token(*flag, token, replacement); + } + for(flag = cons->second.no_flag.begin(); flag != cons->second.no_flag.end(); flag++) { + replace_token(*flag, token, replacement); + } + for(flag = cons->second.has_flag.begin(); flag != cons->second.has_flag.end(); flag++) { + replace_token(*flag, token, replacement); + } + replace_token(cons->second.images, token, replacement); + } + + replace_token(rule.images, token, replacement); +} + terrain_builder::building_rule terrain_builder::rotate_rule(const terrain_builder::building_rule &rule, - int angle, const std::string &angle_name) + int angle, const std::vector& rot) { building_rule ret; - ret.image_foreground = rule.image_foreground; - ret.image_background = rule.image_background; + if(rot.size() != 6) { + std::cerr << "Error: invalid rotations\n"; + return ret; + } + ret.images = rule.images; ret.location_constraints = rule.location_constraints; ret.probability = rule.probability; + ret.precedence = rule.precedence; - building_rule::constraint_set::const_iterator cons; + constraint_set::const_iterator cons; for(cons = rule.constraints.begin(); cons != rule.constraints.end(); ++cons) { const terrain_constraint &rcons = rotate(cons->second, angle); ret.constraints[rcons.loc] = rcons; @@ -136,7 +176,7 @@ terrain_builder::building_rule terrain_builder::rotate_rule(const terrain_builde int minx = INT_MAX; int miny = INT_MAX; - building_rule::constraint_set::iterator cons2; + constraint_set::iterator cons2; for(cons2 = ret.constraints.begin(); cons2 != ret.constraints.end(); ++cons2) { minx = minimum(cons2->second.loc.x, minx); miny = minimum(2*cons2->second.loc.y + (cons2->second.loc.x & 1), miny); @@ -150,31 +190,42 @@ terrain_builder::building_rule terrain_builder::rotate_rule(const terrain_builde for(cons2 = ret.constraints.begin(); cons2 != ret.constraints.end(); ++cons2) { //Adjusts positions cons2->second.loc += gamemap::location(-minx, -((miny-1)/2)); - - //Transforms attributes - std::vector::iterator flag; - - for(flag = cons2->second.set_flag.begin(); flag != cons2->second.set_flag.end(); flag++) { - replace_rotation(*flag, angle_name); - } - for(flag = cons2->second.no_flag.begin(); flag != cons2->second.no_flag.end(); flag++) { - replace_rotation(*flag, angle_name); - } - for(flag = cons2->second.has_flag.begin(); flag != cons2->second.has_flag.end(); flag++) { - replace_rotation(*flag, angle_name); - } } - replace_rotation(ret.image_foreground, angle_name); - replace_rotation(ret.image_background, angle_name); - + for(int i = 0; i < 6; ++i) { + int a = (angle+i) % 6; + std::string token = "@R"; + token.push_back('0' + i); + replace_token(ret, token, rot[a]); + } + return ret; } -void terrain_builder::add_constraint_item(std::vector &list, const std::string &item) +terrain_builder::building_rule terrain_builder::rule_from_terrain_template(const terrain_builder::building_rule&tpl, const gamemap::TERRAIN terrain) { - if(!item.empty()) - list.push_back(item); + terrain_builder::building_rule ret = tpl; + + std::string ter(1, terrain); + constraint_set::iterator cons; + for(cons = ret.constraints.begin(); cons != ret.constraints.end(); ++cons) { + replace_token(cons->second.terrain_types, "@", ter); + } + replace_token(ret, "@T", map_.get_terrain_info(terrain).default_image()); + + return ret; +} + +void terrain_builder::add_images_from_config(imagelist& images, const config &cfg) +{ + const config::child_list& cimages = cfg.get_children("image"); + + for(config::child_list::const_iterator itor = cimages.begin(); itor != cimages.end(); ++itor) { + const int z_index = atoi((**itor)["z_index"].c_str()); + const std::string &name = (**itor)["name"]; + + images.insert(std::pair(z_index, name)); + } } void terrain_builder::add_constraints(std::map & constraints, @@ -185,18 +236,34 @@ void terrain_builder::add_constraints(std::map &constraints, - const gamemap::location& loc, const config& cfg) +void terrain_builder::add_constraint_item(std::vector &list, const config& cfg, const std::string &item) +{ + if(!cfg[item].empty()) + list.push_back(cfg[item]); + + const config::child_list& items = cfg.get_children(item); + + for(config::child_list::const_iterator itor = items.begin(); itor != items.end(); ++itor) { + if(!(**itor)["name"].empty()) + list.push_back((**itor)["name"]); + } +} + +void terrain_builder::add_constraints(terrain_builder::constraint_set &constraints, const gamemap::location& loc, const config& cfg) { add_constraints(constraints, loc, cfg["type"]); - add_constraint_item(constraints[loc].set_flag, cfg["set_flag"]); - add_constraint_item(constraints[loc].has_flag, cfg["has_flag"]); - add_constraint_item(constraints[loc].no_flag, cfg["no_flag"]); + terrain_constraint& constraint = constraints[loc]; + + add_constraint_item(constraint.set_flag, cfg, "set_flag"); + add_constraint_item(constraint.has_flag, cfg, "has_flag"); + add_constraint_item(constraint.no_flag, cfg, "no_flag"); + + add_images_from_config(constraint.images, cfg); } void terrain_builder::parse_mapstring(const std::string &mapstring, struct building_rule &br, @@ -262,22 +329,39 @@ void terrain_builder::parse_mapstring(const std::string &mapstring, struct build } +void terrain_builder::add_rotated_rules(building_ruleset& rules, const building_rule& tpl, const std::string &rotations) +{ + + if(rotations.empty()) { + // Adds the parsed built terrain to the list + building_rules_.insert(std::pair(tpl.precedence, tpl)); + } else { + const std::vector& rot = config::split(rotations, ','); + + for(int angle = 0; angle < rot.size(); angle++) { + building_rules_.insert(std::pair(tpl.precedence, + rotate_rule(tpl, angle, rot))); + } + } +} + void terrain_builder::parse_config(const config &cfg) { log_scope("terrain_builder::parse_config"); //Parses the list of building rules (BRs) - config::child_list brs(cfg.get_children("building_rule")); + const config::child_list& brs = cfg.get_children("terrain_graphics"); for(config::child_list::const_iterator br = brs.begin(); br != brs.end(); ++br) { building_rule pbr; // Parsed Building rule - pbr.image_foreground = (**br)["image_foreground"]; - pbr.image_background = (**br)["image_background"]; + add_images_from_config(pbr.images, **br); + if(!((**br)["x"].empty() || (**br)["y"].empty())) pbr.location_constraints = gamemap::location(atoi((**br)["x"].c_str()), atoi((**br)["y"].c_str())); pbr.probability = (**br)["probability"].empty() ? -1 : atoi((**br)["probability"].c_str()); + pbr.precedence = (**br)["precedence"].empty() ? 0 : atoi((**br)["precedence"].c_str()); //Mapping anchor indices to anchor locations. anchormap anchors; @@ -322,7 +406,7 @@ void terrain_builder::parse_config(const config &cfg) const std::string global_no_flag = (**br)["no_flag"]; const std::string global_has_flag = (**br)["has_flag"]; - for(building_rule::constraint_set::iterator constraint = pbr.constraints.begin(); constraint != pbr.constraints.end(); + for(constraint_set::iterator constraint = pbr.constraints.begin(); constraint != pbr.constraints.end(); constraint++) { if(global_set_flag.size()) @@ -338,25 +422,29 @@ void terrain_builder::parse_config(const config &cfg) // Handles rotations const std::string rotations = (**br)["rotations"]; - if(rotations.size()) { - const std::vector& rot = config::split(rotations, ','); - - for(int angle = 0; angle < rot.size(); angle++) { - building_rules_.push_back(rotate_rule(pbr, angle, rot[angle])); - } + const std::string terrains = (**br)["terrains"]; + + if(terrains.empty()) { + add_rotated_rules(building_rules_, pbr, rotations); } else { - // Adds the parsed built terrain to the list - building_rules_.push_back(pbr); + for(std::string::const_iterator terrain = terrains.begin(); + terrain != terrains.end(); ++terrain) { + + const building_rule r = rule_from_terrain_template(pbr, *terrain); + add_rotated_rules(building_rules_, r, rotations); + } } + } +#if 0 std::cerr << "Built terrain rules: \n"; building_ruleset::const_iterator rule; for(rule = building_rules_.begin(); rule != building_rules_.end(); ++rule) { - std::cerr << ">> New rule: image_background = " << rule->image_background << " , image_foreground = "<< rule->image_foreground << "\n"; - for(building_rule::constraint_set::const_iterator constraint = rule->constraints.begin(); - constraint != rule->constraints.end(); ++constraint) { + std::cerr << ">> New rule: image_background = " /* << rule->second.image_background << " , image_foreground = "<< rule->second.image_foreground */ << "\n"; + for(constraint_set::const_iterator constraint = rule->second.constraints.begin(); + constraint != rule->second.constraints.end(); ++constraint) { std::cerr << ">>>> New constraint: location = (" << constraint->second.loc.x << ", " << constraint->second.loc.y << "), terrain types = " << constraint->second.terrain_types << "\n"; @@ -372,6 +460,7 @@ void terrain_builder::parse_config(const config &cfg) } } +#endif } @@ -388,7 +477,7 @@ bool terrain_builder::rule_matches(const terrain_builder::building_rule &rule, c return false; } - for(building_rule::constraint_set::const_iterator cons = rule.constraints.begin(); + for(constraint_set::const_iterator cons = rule.constraints.begin(); cons != rule.constraints.end(); ++cons) { // translated location @@ -399,9 +488,11 @@ bool terrain_builder::rule_matches(const terrain_builder::building_rule &rule, c const tile& btile = tile_map_[tloc]; - if(!map_.get_terrain_info(tloc).matches(cons->second.terrain_types)) - return false; - + if(!cons->second.terrain_types.empty()) { + if(!map_.get_terrain_info(tloc).matches(cons->second.terrain_types)) + return false; + } + std::vector::const_iterator itor; for(itor = cons->second.no_flag.begin(); itor != cons->second.no_flag.end(); ++itor) { @@ -422,7 +513,7 @@ bool terrain_builder::rule_matches(const terrain_builder::building_rule &rule, c void terrain_builder::apply_rule(const terrain_builder::building_rule &rule, const gamemap::location &loc) { - for(building_rule::constraint_set::const_iterator constraint = rule.constraints.begin(); + for(constraint_set::const_iterator constraint = rule.constraints.begin(); constraint != rule.constraints.end(); ++constraint) { const gamemap::location tloc = loc + constraint->second.loc; @@ -431,17 +522,28 @@ void terrain_builder::apply_rule(const terrain_builder::building_rule &rule, con tile& btile = tile_map_[tloc]; - if(rule.image_foreground.size()) { - image::locator th(rule.image_foreground, constraint->second.loc); - btile.images_foreground.push_back(th); + std::multimap::const_iterator img; + + for(img = rule.images.begin(); img != rule.images.end(); ++img) { + image::locator th(img->second, constraint->second.loc); + if(img->first < 0) { + btile.images_background.push_back(th); + } else { + btile.images_foreground.push_back(th); + } + } - if(rule.image_background.size()) { - image::locator th(rule.image_background, constraint->second.loc); - btile.images_background.push_back(th); + for(img = constraint->second.images.begin(); img != constraint->second.images.end(); ++img) { + image::locator th(img->second); + if(img->first < 0) { + btile.images_background.push_back(th); + } else { + btile.images_foreground.push_back(th); + } } - + // Sets flags for(std::vector::const_iterator itor = constraint->second.set_flag.begin(); itor != constraint->second.set_flag.end(); itor++) { btile.flags.insert(*itor); @@ -468,36 +570,79 @@ void terrain_builder::build_terrains() building_ruleset::const_iterator rule; for(rule = building_rules_.begin(); rule != building_rules_.end(); ++rule) { + //if the rule has no constraints, it is invalid + if(rule->second.constraints.empty()) + continue; - //find a constraint that contains an unique terrain type on the current - //rule - building_rule::constraint_set::const_iterator constraint; - for(constraint = rule->constraints.begin(); - constraint != rule->constraints.end(); ++constraint) { - - if(constraint->second.terrain_types.size() == 1 && (constraint->second.terrain_types[0] != '*')) { - break; + //checks if all the images referenced by the current rule are valid. + //if not, this rule will not match. + bool absent_image = false; + imagelist::const_iterator image; + constraint_set::const_iterator constraint; + + for(image = rule->second.images.begin(); + !absent_image && (image != rule->second.images.end()); ++image) { + + if(!image::exists("terrain/" + image->second + ".png")) + absent_image = true; + } + + for(constraint = rule->second.constraints.begin(); + constraint != rule->second.constraints.end(); ++constraint) { + for(image = constraint->second.images.begin(); + !absent_image && (image != constraint->second.images.end()); + ++image) { + if(!image::exists("terrain/" + image->second + ".png")) + absent_image = true; } } - if(constraint != rule->constraints.end()) { - gamemap::TERRAIN c = constraint->second.terrain_types[0]; - gamemap::location loc = constraint->second.loc; - const std::vector& locations = terrain_by_type_[c]; + if(absent_image) + continue; + + //find the constraint that contains the less terrain of all terrain rules + constraint_set::const_iterator smallest_constraint; + int smallest_constraint_size = INT_MAX; + + for(constraint = rule->second.constraints.begin(); + constraint != rule->second.constraints.end(); ++constraint) { + + const std::string &types = constraint->second.terrain_types; - for(std::vector::const_iterator itor = locations.begin(); - itor != locations.end(); ++itor) { + if(types.empty()) + continue; + if(types[0] == '!') + continue; + if(types.find('*') != std::string::npos) + continue; + if(types.size() >= smallest_constraint_size) + continue; + + smallest_constraint_size = types.size(); + smallest_constraint = constraint; + } + + if(smallest_constraint_size != INT_MAX) { + const std::string &types = smallest_constraint->second.terrain_types; + const gamemap::location loc = smallest_constraint->second.loc; + + for(std::string::const_iterator c = types.begin(); c != types.end(); ++c) { + const std::vector& locations = terrain_by_type_[*c]; + + for(std::vector::const_iterator itor = locations.begin(); + itor != locations.end(); ++itor) { - if(rule_matches(*rule, *itor - loc, rule_index)) { - apply_rule(*rule, *itor - loc); + if(rule_matches(rule->second, *itor - loc, rule_index)) { + apply_rule(rule->second, *itor - loc); + } } } } else { - for(int x = -5; x <= map_.x() + 4; ++x) { - for(int y = 51; y <= map_.y() + 4; ++y) { + for(int x = -1; x <= map_.x(); ++x) { + for(int y = -1; y <= map_.y(); ++y) { const gamemap::location loc(x,y); - if(rule_matches(*rule, loc, rule_index)) - apply_rule(*rule, loc); + if(rule_matches(rule->second, loc, rule_index)) + apply_rule(rule->second, loc); } } } diff --git a/src/builder.hpp b/src/builder.hpp index b4c8e4da7c7..0d3eb664579 100644 --- a/src/builder.hpp +++ b/src/builder.hpp @@ -33,10 +33,14 @@ public: //built content for this tile. //Returns NULL if there is no built content for this tile. const std::vector *get_terrain_at(const gamemap::location &loc, - ADJACENT_TERRAIN_TYPE terrain_type) const; + ADJACENT_TERRAIN_TYPE terrain_type) const; + + // regenerate the generated content at the given location. void rebuild_terrain(const gamemap::location &loc); + typedef std::multimap imagelist; + struct terrain_constraint { terrain_constraint() : loc() {}; @@ -48,8 +52,10 @@ public: std::vector set_flag; std::vector no_flag; std::vector has_flag; - }; + imagelist images; + }; + struct tile { std::set flags; @@ -60,16 +66,17 @@ public: }; private: + typedef std::map constraint_set; struct building_rule { - typedef std::map constraint_set; constraint_set constraints; gamemap::location location_constraints; int probability; - std::string image_foreground; - std::string image_background; + int precedence; + + imagelist images; }; struct tilemap @@ -88,21 +95,28 @@ private: int y_; }; + typedef std::multimap building_ruleset; + terrain_constraint rotate(const terrain_constraint &constraint, int angle); - void replace_rotation(std::string &s, const std::string &replacement); + void replace_token(std::string &, const std::string &token, const std::string& replacement); + void replace_token(imagelist &, const std::string &token, const std::string& replacement); + void replace_token(building_rule &s, const std::string &token, const std::string& replacement); - building_rule rotate_rule(const building_rule &rule, int angle, const std::string &angle_name); + building_rule rotate_rule(const building_rule &rule, int angle, const std::vector& angle_name); + void add_rotated_rules(building_ruleset& rules, const building_rule& tpl, const std::string &rotations); + void add_constraint_item(std::vector &list, const config& cfg, const std::string &item); + + void terrain_builder::add_images_from_config(imagelist &images, const config &cfg); - void add_constraint_item(std::vector &list, const std::string &item); void add_constraints(std::map& constraints, const gamemap::location &loc, const std::string& type); void add_constraints(std::map& constraints, const gamemap::location &loc, const config &cfg); - + typedef std::multimap anchormap; void parse_mapstring(const std::string &mapstring, struct building_rule &br, anchormap& anchors); - + terrain_builder::building_rule rule_from_terrain_template(const terrain_builder::building_rule &tpl, const gamemap::TERRAIN terrain); void parse_config(const config &cfg); bool rule_matches(const building_rule &rule, const gamemap::location &loc, int rule_index); void apply_rule(const building_rule &rule, const gamemap::location &loc); @@ -113,8 +127,7 @@ private: typedef std::map > terrain_by_type_map; terrain_by_type_map terrain_by_type_; - - typedef std::vector building_ruleset; + building_ruleset building_rules_; }; diff --git a/src/display.cpp b/src/display.cpp index 9b3a6090a7a..a1b5cbc17af 100644 --- a/src/display.cpp +++ b/src/display.cpp @@ -912,7 +912,7 @@ void display::draw_unit_details(int x, int y, const gamemap::location& loc, void display::draw_minimap(int x, int y, int w, int h) { - const scoped_sdl_surface surface(getMinimap(w,h)); + const scoped_sdl_surface surface(get_minimap(w,h)); if(surface == NULL) return; @@ -957,6 +957,7 @@ void display::draw_minimap(int x, int y, int w, int h) update_rect(minimap_location); } +#if 0 void display::draw_terrain_palette(int x, int y, gamemap::TERRAIN selected) { const int max_h = 35; @@ -971,7 +972,7 @@ void display::draw_terrain_palette(int x, int y, gamemap::TERRAIN selected) std::vector terrains = map_.get_terrain_precedence(); for(std::vector::const_iterator i = terrains.begin(); i != terrains.end(); ++i) { - const scoped_sdl_surface image(getTerrain(*i,image::SCALED,-1,-1)); + const scoped_sdl_surface image(get_terrain(*i,image::SCALED,-1,-1)); if(image == NULL) { std::cerr << "image for terrain '" << *i << "' not found\n"; return; @@ -1004,6 +1005,7 @@ void display::draw_terrain_palette(int x, int y, gamemap::TERRAIN selected) invalid_rect.h = y - invalid_rect.y; update_rect(invalid_rect); } +#endif gamemap::TERRAIN display::get_terrain_on(int palx, int paly, int x, int y) { @@ -1265,7 +1267,7 @@ void display::draw_bar(const std::string& image, int xpos, int ypos, size_t heig blit_surface(xpos,ypos,surf,&top); blit_surface(xpos,ypos+top.h,surf,&bot); - const size_t unfilled = height*(1.0 - filled); + const size_t unfilled = (const size_t)(height*(1.0 - filled)); if(unfilled < height && alpha >= 0.3) { SDL_Rect filled_area = {xpos+bar_loc.x,ypos+bar_loc.y+unfilled,bar_loc.w,height-unfilled}; @@ -1274,6 +1276,7 @@ void display::draw_bar(const std::string& image, int xpos, int ypos, size_t heig } } +#if 0 void display::draw_tile_adjacent(int x, int y, image::TYPE image_type, ADJACENT_TERRAIN_TYPE type) { const gamemap::location loc(x,y); @@ -1306,6 +1309,34 @@ void display::draw_tile_adjacent(int x, int y, image::TYPE image_type, ADJACENT_ SDL_BlitSurface(*i,NULL,dst,&dstrect); } } +#endif + +void display::draw_terrain_on_tile(int x, int y, image::TYPE image_type, ADJACENT_TERRAIN_TYPE type) +{ + + const gamemap::location loc(x,y); + int xpos = int(get_location_x(loc)); + int ypos = int(get_location_y(loc)); + + SDL_Rect clip_rect = map_area(); + + if(xpos > clip_rect.x + clip_rect.w || ypos > clip_rect.y + clip_rect.h || + xpos + zoom_ < clip_rect.x || ypos + zoom_ < clip_rect.y) { + return; + } + + SDL_Surface* const dst = screen_.getSurface(); + + clip_rect_setter set_clip_rect(dst,clip_rect); + + const std::vector& images = get_terrain_images(x,y,image_type,type); + + std::vector::const_iterator itor; + for(itor = images.begin(); itor != images.end(); ++itor) { + SDL_Rect dstrect = { xpos, ypos, 0, 0 }; + SDL_BlitSurface(*itor,NULL,dst,&dstrect); + } +} void display::draw_tile(int x, int y, SDL_Surface* unit_image, double alpha, Uint32 blend_to) { @@ -1363,7 +1394,8 @@ void display::draw_tile(int x, int y, SDL_Surface* unit_image, double alpha, Uin image_type = image::SEMI_BRIGHTENED; } - scoped_sdl_surface surface(getTerrain(terrain,image_type,x,y)); +#if 0 + scoped_sdl_surface surface(get_terrain(terrain,image_type,x,y)); if(surface == NULL) { std::cerr << "Could not get terrain surface\n"; @@ -1376,16 +1408,17 @@ void display::draw_tile(int x, int y, SDL_Surface* unit_image, double alpha, Uin //initialized to pass to each call to SDL_BlitSurface SDL_Rect dstrect = { xpos, ypos, 0, 0 }; SDL_BlitSurface(surface,NULL,dst,&dstrect); +#endif if(!is_shrouded) { - scoped_sdl_surface flag(getFlag(terrain,x,y)); + draw_terrain_on_tile(x,y,image_type,ADJACENT_BACKGROUND); + + scoped_sdl_surface flag(get_flag(terrain,x,y)); if(flag != NULL) { SDL_Rect dstrect = { xpos, ypos, 0, 0 }; SDL_BlitSurface(flag,NULL,dst,&dstrect); } - draw_tile_adjacent(x,y,image_type,ADJACENT_BACKGROUND); - typedef std::multimap::const_iterator Itor; for(std::pair overlays = overlays_.equal_range(loc); @@ -1393,15 +1426,26 @@ void display::draw_tile(int x, int y, SDL_Surface* unit_image, double alpha, Uin scoped_sdl_surface overlay_surface(image::get_image(overlays.first->second)); + //note that dstrect can be changed by SDL_BlitSurface and so a + //new instance should be initialized to pass to each call to + //SDL_BlitSurface if(overlay_surface != NULL) { SDL_Rect dstrect = { xpos, ypos, 0, 0 }; SDL_BlitSurface(overlay_surface,NULL,dst,&dstrect); } } - } - - if(!is_shrouded) { draw_footstep(loc,xpos,ypos); + } else { + //FIXME: shouldn't void.png and fog.png be in the program configuration? + scoped_sdl_surface surface(image::get_image("terrain/void.png")); + + if(surface == NULL) { + std::cerr << "Could not get void surface!\n"; + return; + } + + SDL_Rect dstrect = { xpos, ypos, 0, 0 }; + SDL_BlitSurface(surface,NULL,dst,&dstrect); } if(fogged(x,y)) { @@ -1415,7 +1459,7 @@ void display::draw_tile(int x, int y, SDL_Surface* unit_image, double alpha, Uin draw_unit_on_tile(x,y,unit_image,alpha,blend_to); if(!shrouded(x,y)) { - draw_tile_adjacent(x,y,image_type,ADJACENT_FOREGROUND); + draw_terrain_on_tile(x,y,image_type,ADJACENT_FOREGROUND); } //draw the time-of-day mask on top of the hex @@ -1450,6 +1494,8 @@ void display::draw_tile(int x, int y, SDL_Surface* unit_image, double alpha, Uin if(cross != NULL) draw_unit(xpos,ypos,cross,false,debugHighlights_[loc],0); } + + update_rect(xpos,ypos,zoom_,zoom_); } void display::draw_footstep(const gamemap::location& loc, int xloc, int yloc) @@ -1544,6 +1590,7 @@ const std::string& get_direction(size_t n) const static std::string dirs[6] = {"-n","-ne","-se","-s","-sw","-nw"}; return dirs[n >= sizeof(dirs)/sizeof(*dirs) ? 0 : n]; } + } bool angle_is_northern(size_t n) @@ -1557,7 +1604,7 @@ const std::string& get_angle_direction(size_t n) const static std::string dirs[6] = {"-ne","-e","-se","-sw","-w","-nw"}; return dirs[n >= sizeof(dirs)/sizeof(*dirs) ? 0 : n]; } - +#if 0 std::vector display::getAdjacentTerrain(int x, int y, image::TYPE image_type, ADJACENT_TERRAIN_TYPE terrain_type) { std::vector res; @@ -1618,7 +1665,7 @@ std::vector display::getAdjacentTerrain(int x, int y, image: for(int n = 0; *terrain == tiles[i] && n != 6; i = (i+1)%6, ++n) { stream << get_direction(i); - const shared_sdl_surface new_surface(getTerrain( + const shared_sdl_surface new_surface(get_terrain( *terrain,image_type,x,y,stream.str())); if(new_surface == NULL) { @@ -1642,8 +1689,79 @@ std::vector display::getAdjacentTerrain(int x, int y, image: return res; } +#endif -std::vector display::getBuiltTerrain(int x, int y, image::TYPE image_type, ADJACENT_TERRAIN_TYPE terrain_type) + +std::vector display::get_fog_shroud_graphics(const gamemap::location& loc) +{ + std::vector res; + + gamemap::location adjacent[6]; + bool transition_done[6]; + get_adjacent_tiles(loc,adjacent); + int tiles[6]; + static const int terrain_types[] = { gamemap::VOID_TERRAIN, gamemap::FOGGED, 0 }; + + for(int i = 0; i != 6; ++i) { + if(shrouded(adjacent[i].x,adjacent[i].y)) + tiles[i] = gamemap::VOID_TERRAIN; + else if(!fogged(loc.x,loc.y) && fogged(adjacent[i].x,adjacent[i].y)) + tiles[i] = gamemap::FOGGED; + else + tiles[i] = 0; + } + + + for(const int * terrain = terrain_types; *terrain != 0; terrain ++) { + //find somewhere that doesn't have overlap to use as a starting point + int start; + for(start = 0; start != 6; ++start) { + if(tiles[start] != *terrain) + break; + } + + if(start == 6) { + start = 0; + } + + //find all the directions overlap occurs from + for(int i = (start+1)%6, n = 0; i != start && n != 6; ++n) { + if(tiles[i] == *terrain) { + std::ostringstream stream; + std::string name; + // if(*terrain == gamemap::VOID_TERRAIN) + // stream << "void"; + //else + // stream << "fog"; + stream << map_.get_terrain_info(*terrain).default_image(); + + for(int n = 0; *terrain == tiles[i] && n != 6; i = (i+1)%6, ++n) { + stream << get_direction(i); + + if(!image::exists("terrain/" + stream.str() + ".png")) { + //if we don't have any surface at all, + //then move onto the next overlapped area + if(name.empty()) + i = (i+1)%6; + break; + } else { + name = stream.str(); + } + } + + if(!name.empty()) { + res.push_back(name); + } + } else { + i = (i+1)%6; + } + } + } + + return res; +} + +std::vector display::get_terrain_images(int x, int y, image::TYPE image_type, ADJACENT_TERRAIN_TYPE terrain_type) { std::vector res; gamemap::location loc(x,y); @@ -1658,17 +1776,34 @@ std::vector display::getBuiltTerrain(int x, int y, image::TY image::locator image = *it; image.filename = "terrain/" + it->filename; - const shared_sdl_surface surface(getTerrain(image,image_type,x,y,true)); + const shared_sdl_surface surface(get_terrain(image,image_type,x,y,true)); if(surface != NULL) { res.push_back(surface); } } } + if(terrain_type == ADJACENT_FOREGROUND) { + const std::vector fog_shroud = get_fog_shroud_graphics(gamemap::location(x,y)); + + if(!fog_shroud.empty()) { + for(std::vector::const_iterator it = fog_shroud.begin(); it != fog_shroud.end(); ++it) { + image::locator image(*it); + image.filename = "terrain/" + *it; + + const shared_sdl_surface surface(get_terrain(image,image_type,x,y,true)); + if(surface != NULL) { + res.push_back(surface); + } + } + + } + } + return res; } -SDL_Surface* display::getTerrain(const image::locator& image, image::TYPE image_type, +SDL_Surface* display::get_terrain(const image::locator& image, image::TYPE image_type, int x, int y, bool search_tod) { SDL_Surface* im = NULL; @@ -1700,18 +1835,18 @@ SDL_Surface* display::getTerrain(const image::locator& image, image::TYPE image_ const int radj = tod_at.red - tod.red; const int gadj = tod_at.green - tod.green; const int badj = tod_at.blue - tod.blue; - + if((radj|gadj|badj) != 0 && im != NULL) { const scoped_sdl_surface backup(im); im = adjust_surface_colour(im,radj,gadj,badj); if(im == NULL) std::cerr << "could not adjust surface..\n"; } - + return im; } - -SDL_Surface* display::getTerrain(gamemap::TERRAIN terrain, image::TYPE image_type, +#if 0 +SDL_Surface* display::get_terrain(gamemap::TERRAIN terrain, image::TYPE image_type, int x, int y, const std::string& direction) { std::string image = "terrain/" + (direction.empty() ? @@ -1720,7 +1855,7 @@ SDL_Surface* display::getTerrain(gamemap::TERRAIN terrain, image::TYPE image_typ image += direction; - SDL_Surface* im = getTerrain(image, image_type, x, y, direction.empty()); + SDL_Surface* im = get_terrain(image, image_type, x, y, direction.empty()); if(im == NULL && direction.empty()) { im = image::get_image("terrain/" + @@ -1729,8 +1864,8 @@ SDL_Surface* display::getTerrain(gamemap::TERRAIN terrain, image::TYPE image_typ return im; } - -SDL_Surface* display::getFlag(gamemap::TERRAIN terrain, int x, int y) +#endif +SDL_Surface* display::get_flag(gamemap::TERRAIN terrain, int x, int y) { const bool village = map_.is_village(terrain); if(!village) @@ -1762,7 +1897,7 @@ void display::blit_surface(int x, int y, SDL_Surface* surface, SDL_Rect* srcrect } } -SDL_Surface* display::getMinimap(int w, int h) +SDL_Surface* display::get_minimap(int w, int h) { if(minimap_ == NULL) { minimap_ = image::getMinimap(w,h,map_, @@ -1820,8 +1955,8 @@ void display::float_label(const gamemap::location& loc, const std::string& text, } void display::draw_unit(int x, int y, SDL_Surface* image, - bool upside_down, double alpha, Uint32 blendto, double submerged, - SDL_Surface* ellipse_back, SDL_Surface* ellipse_front) + bool upside_down, double alpha, Uint32 blendto, double submerged, + SDL_Surface* ellipse_back, SDL_Surface* ellipse_front) { //calculate the y position of the ellipse. It should be the same as the y position of the image, unless //the image is partially submerged, in which case the ellipse should appear to float 'on top of' the water diff --git a/src/display.hpp b/src/display.hpp index 8cdd1f4a0bb..100c2b28135 100644 --- a/src/display.hpp +++ b/src/display.hpp @@ -175,13 +175,17 @@ public: int red, int green, int blue); private: + enum ADJACENT_TERRAIN_TYPE { ADJACENT_BACKGROUND, ADJACENT_FOREGROUND }; + + //composes and draws the terrains on a tile + void draw_terrain_on_tile(int x, int y, image::TYPE image_type, ADJACENT_TERRAIN_TYPE type); + void draw_unit_on_tile(int x, int y, SDL_Surface* unit_image=NULL, double alpha=1.0, Uint32 blend_to=0); void draw_halo_on_tile(int x, int y); - enum ADJACENT_TERRAIN_TYPE { ADJACENT_BACKGROUND, ADJACENT_FOREGROUND }; - void draw_tile_adjacent(int x, int y, image::TYPE image_type, ADJACENT_TERRAIN_TYPE type); + // void draw_tile_adjacent(int x, int y, image::TYPE image_type, ADJACENT_TERRAIN_TYPE type); public: @@ -239,7 +243,7 @@ public: void update_display(); //functions used in the editor. - void draw_terrain_palette(int x, int y, gamemap::TERRAIN selected); + //void draw_terrain_palette(int x, int y, gamemap::TERRAIN selected); gamemap::TERRAIN get_terrain_on(int palx, int paly, int x, int y); //set_team sets the team controlled by the player using the computer, @@ -351,21 +355,23 @@ private: void bounds_check_position(); - std::vector getAdjacentTerrain(int x, int y, image::TYPE type, ADJACENT_TERRAIN_TYPE terrain_type); - std::vector getBuiltTerrain(int x, int y, image::TYPE type, ADJACENT_TERRAIN_TYPE terrain_type); + // std::vector getAdjacentTerrain(int x, int y, image::TYPE type, ADJACENT_TERRAIN_TYPE terrain_type); + std::vector get_terrain_images(int x, int y, image::TYPE type, ADJACENT_TERRAIN_TYPE terrain_type); + std::vector get_fog_shroud_graphics(const gamemap::location& loc); + //this surface must be freed by the caller - SDL_Surface* getTerrain(gamemap::TERRAIN, image::TYPE type, - int x, int y, const std::string& dir=""); + //SDL_Surface* get_terrain(gamemap::TERRAIN, image::TYPE type, + // int x, int y, const std::string& dir=""); //this surface must be freed by the caller - SDL_Surface* getTerrain(const image::locator &image, image::TYPE type, + SDL_Surface* get_terrain(const image::locator &image, image::TYPE type, int x, int y, bool search_tod); //this surface must be freed by the caller - SDL_Surface* getFlag(gamemap::TERRAIN, int x, int y); + SDL_Surface* get_flag(gamemap::TERRAIN, int x, int y); //this surface must be freed by the caller - SDL_Surface* getMinimap(int w, int h); + SDL_Surface* get_minimap(int w, int h); CVideo& screen_; mutable CKey keys_; diff --git a/src/image.cpp b/src/image.cpp index eec444ea6e2..69fa0b878de 100644 --- a/src/image.cpp +++ b/src/image.cpp @@ -22,6 +22,8 @@ typedef std::map image_map; image_map images_,scaledImages_,unmaskedImages_,greyedImages_; image_map brightenedImages_,semiBrightenedImages_; +std::map image_existance_map; + std::map reversedImages_; int red_adjust = 0, green_adjust = 0, blue_adjust = 0; @@ -95,31 +97,41 @@ void flush_cache() clear_surfaces(reversedImages_); } +std::vector get_search_locations(const std::string &file) +{ + std::vector ret; + + static const std::string images_path = "images/"; + const std::string image_filename = images_path + file; + + if(!game_config::path.empty()) { + ret.push_back(game_config::path + "/" + image_filename); + } + + ret.push_back(image_filename); + + ret.push_back(get_user_data_dir() + "/" + image_filename); + + return ret; +} + SDL_Surface* load_image_file(image::locator i_locator) { SDL_Surface* surf = NULL; - static const std::string images_path = "images/"; - const std::string images_filename = images_path + i_locator.filename; + const std::vector& locations = get_search_locations(i_locator.filename); + for(std::vector::const_iterator itor = locations.begin(); + itor != locations.end(); ++itor) { - if(game_config::path.empty() == false) { - const std::string& fullpath = game_config::path + "/" + - images_filename; - surf = IMG_Load(fullpath.c_str()); - } - - if(surf == NULL) { - surf = IMG_Load(images_filename.c_str()); - } - - if(surf == NULL) { - const std::string user_image = get_user_data_dir() + "/" + images_filename; - surf = IMG_Load(user_image.c_str()); + surf = IMG_Load(itor->c_str()); + if(surf != NULL) + return surf; } return surf; } + SDL_Surface * load_image_sub_file(image::locator i_locator) { SDL_Surface *surf = NULL; @@ -434,6 +446,29 @@ void register_image(const std::string &id, SDL_Surface* surf) register_image(locator(id), surf); } +bool exists(const image::locator& i_locator) +{ + bool ret=false; + + if(i_locator.type != image::locator::FILE && + i_locator.type != image::locator::SUB_FILE) + return false; + + if(image_existance_map.find(i_locator) != image_existance_map.end()) + return image_existance_map[i_locator]; + + const std::vector& locations = get_search_locations(i_locator.filename); + for(std::vector::const_iterator itor = locations.begin(); + itor != locations.end(); ++itor) { + + if(file_exists(*itor)) + ret = true; + } + image_existance_map[i_locator] = ret; + + return ret; +} + SDL_Surface* getMinimap(int w, int h, const gamemap& map, int lawful_bonus, const team* tm) { diff --git a/src/image.hpp b/src/image.hpp index 2964965aa42..19b6159fbf3 100644 --- a/src/image.hpp +++ b/src/image.hpp @@ -100,6 +100,9 @@ namespace image { ///and replaced with this image. void register_image(const locator& i_locator, SDL_Surface* surf); + //returns true if the given image actually exists, without loading it. + bool exists(const locator& i_locator); + ///function to create the minimap for a given map ///the surface returned must be freed by the user SDL_Surface* getMinimap(int w, int h, const gamemap& map_, int lawful_bonus, const team* tm=NULL); diff --git a/src/replay.cpp b/src/replay.cpp index f3efcf61ce6..c55645a43bc 100644 --- a/src/replay.cpp +++ b/src/replay.cpp @@ -626,7 +626,8 @@ bool do_replay(display& disp, const gamemap& map, const game_data& gameinfo, const std::string& team_name = (*child)["team_name"]; if(team_name == "" || teams[disp.viewing_team()].team_name() == team_name) { if(preferences::message_bell()) { - sound::play_sound(game_config::sounds::receive_message); + if(!replayer.skipping()) + sound::play_sound(game_config::sounds::receive_message); } const int side = lexical_cast_default((*child)["side"].c_str()); diff --git a/src/terrain.cpp b/src/terrain.cpp index e2838c7bb85..017c7367022 100644 --- a/src/terrain.cpp +++ b/src/terrain.cpp @@ -59,16 +59,17 @@ terrain_type::terrain_type(const config& cfg) castle_ = cfg["recruit_onto"] == "true"; keep_ = cfg["recruit_from"] == "true"; } - +#if 0 const std::string& terrain_type::image(int x, int y) const { assert(!images_.empty()); - - return images_[(((x<<8)^3413402)+y^34984 + x*y)%images_.size()]; + //return images_[(((x<<8)^3413402)+y^34984 + x*y)%images_.size()]; + return default_image(); } - +#endif const std::string& terrain_type::default_image() const { + //static const std::string ret = "void"; assert(!images_.empty()); return images_.front(); } diff --git a/src/terrain.hpp b/src/terrain.hpp index 7d43ba9db62..91900c85931 100644 --- a/src/terrain.hpp +++ b/src/terrain.hpp @@ -24,7 +24,7 @@ public: terrain_type(); terrain_type(const config& cfg); - const std::string& image(int x, int y) const; + //const std::string& image(int x, int y) const; const std::string& default_image() const; const std::string& adjacent_image() const; const std::string& name() const;