mirror of
https://github.com/AndorsTrailRelease/andors-trail.git
synced 2026-01-06 19:45:42 +01:00
@@ -26,14 +26,30 @@
|
||||
{
|
||||
"itemID":"bone",
|
||||
"chance":"30",
|
||||
"quantity":{
|
||||
"min":1,
|
||||
"max":2
|
||||
}
|
||||
},
|
||||
{
|
||||
"itemID":"gold",
|
||||
"chance":"70",
|
||||
"quantity":{
|
||||
"min":1,
|
||||
"max":6
|
||||
}
|
||||
},
|
||||
{
|
||||
"itemID":"club1",
|
||||
"chance":"10",
|
||||
"quantity":{
|
||||
"min":1,
|
||||
"max":1
|
||||
}
|
||||
},
|
||||
{
|
||||
"itemID":"marrowtaint",
|
||||
"chance":"1/1000",
|
||||
"itemID":"shield_iron1",
|
||||
"chance":"5",
|
||||
"quantity":{
|
||||
"min":1,
|
||||
"max":1
|
||||
|
||||
@@ -118,11 +118,15 @@
|
||||
"increaseAttackCost":0,
|
||||
"increaseAttackChance":-6,
|
||||
"increaseBlockChance":10,
|
||||
"increaseDamageResistance":1,
|
||||
"addedConditions":[
|
||||
"increaseDamageResistance":1
|
||||
},
|
||||
"hitReceivedEffect":{
|
||||
"conditionsSource":[
|
||||
{
|
||||
"condition":"barkskin",
|
||||
"magnitude":3
|
||||
"magnitude":2,
|
||||
"duration":2,
|
||||
"chance":"20"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,188 +1,187 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE map SYSTEM "http://mapeditor.org/dtd/1.0/map.dtd">
|
||||
<map version="1.0" orientation="orthogonal" width="21" height="30" tilewidth="32" tileheight="32">
|
||||
<map version="2017.05.26" orientation="orthogonal" renderorder="right-down" width="21" height="30" tilewidth="32" tileheight="32" nextobjectid="52">
|
||||
<properties>
|
||||
<property name="colorfilter" value="none"/>
|
||||
<property name="outdoors" value="1"/>
|
||||
</properties>
|
||||
<tileset firstgid="1" name="map_bed_1" tilewidth="32" tileheight="32">
|
||||
<tileset firstgid="1" name="map_bed_1" tilewidth="32" tileheight="32" tilecount="128" columns="16">
|
||||
<image source="../drawable/map_bed_1.png" width="512" height="256"/>
|
||||
</tileset>
|
||||
<tileset firstgid="129" name="map_border_1" tilewidth="32" tileheight="32">
|
||||
<tileset firstgid="129" name="map_border_1" tilewidth="32" tileheight="32" tilecount="128" columns="16">
|
||||
<image source="../drawable/map_border_1.png" width="512" height="256"/>
|
||||
</tileset>
|
||||
<tileset firstgid="257" name="map_bridge_1" tilewidth="32" tileheight="32">
|
||||
<tileset firstgid="257" name="map_bridge_1" tilewidth="32" tileheight="32" tilecount="128" columns="16">
|
||||
<image source="../drawable/map_bridge_1.png" width="512" height="256"/>
|
||||
</tileset>
|
||||
<tileset firstgid="385" name="map_bridge_2" tilewidth="32" tileheight="32">
|
||||
<tileset firstgid="385" name="map_bridge_2" tilewidth="32" tileheight="32" tilecount="128" columns="16">
|
||||
<image source="../drawable/map_bridge_2.png" width="512" height="256"/>
|
||||
</tileset>
|
||||
<tileset firstgid="513" name="map_broken_1" tilewidth="32" tileheight="32">
|
||||
<tileset firstgid="513" name="map_broken_1" tilewidth="32" tileheight="32" tilecount="128" columns="16">
|
||||
<image source="../drawable/map_broken_1.png" width="512" height="256"/>
|
||||
</tileset>
|
||||
<tileset firstgid="641" name="map_cavewall_1" tilewidth="32" tileheight="32">
|
||||
<tileset firstgid="641" name="map_cavewall_1" tilewidth="32" tileheight="32" tilecount="108" columns="18">
|
||||
<image source="../drawable/map_cavewall_1.png" width="576" height="192"/>
|
||||
</tileset>
|
||||
<tileset firstgid="749" name="map_cavewall_2" tilewidth="32" tileheight="32">
|
||||
<tileset firstgid="749" name="map_cavewall_2" tilewidth="32" tileheight="32" tilecount="108" columns="18">
|
||||
<image source="../drawable/map_cavewall_2.png" width="576" height="192"/>
|
||||
</tileset>
|
||||
<tileset firstgid="857" name="map_cavewall_3" tilewidth="32" tileheight="32">
|
||||
<tileset firstgid="857" name="map_cavewall_3" tilewidth="32" tileheight="32" tilecount="108" columns="18">
|
||||
<image source="../drawable/map_cavewall_3.png" width="576" height="192"/>
|
||||
</tileset>
|
||||
<tileset firstgid="965" name="map_cavewall_4" tilewidth="32" tileheight="32">
|
||||
<tileset firstgid="965" name="map_cavewall_4" tilewidth="32" tileheight="32" tilecount="108" columns="18">
|
||||
<image source="../drawable/map_cavewall_4.png" width="576" height="192"/>
|
||||
</tileset>
|
||||
<tileset firstgid="1073" name="map_chair_table_1" tilewidth="32" tileheight="32">
|
||||
<tileset firstgid="1073" name="map_chair_table_1" tilewidth="32" tileheight="32" tilecount="128" columns="16">
|
||||
<image source="../drawable/map_chair_table_1.png" width="512" height="256"/>
|
||||
</tileset>
|
||||
<tileset firstgid="1201" name="map_chair_table_2" tilewidth="32" tileheight="32">
|
||||
<tileset firstgid="1201" name="map_chair_table_2" tilewidth="32" tileheight="32" tilecount="128" columns="16">
|
||||
<image source="../drawable/map_chair_table_2.png" width="512" height="256"/>
|
||||
</tileset>
|
||||
<tileset firstgid="1329" name="map_crate_1" tilewidth="32" tileheight="32">
|
||||
<tileset firstgid="1329" name="map_crate_1" tilewidth="32" tileheight="32" tilecount="128" columns="16">
|
||||
<image source="../drawable/map_crate_1.png" width="512" height="256"/>
|
||||
</tileset>
|
||||
<tileset firstgid="1457" name="map_cupboard_1" tilewidth="32" tileheight="32">
|
||||
<tileset firstgid="1457" name="map_cupboard_1" tilewidth="32" tileheight="32" tilecount="128" columns="16">
|
||||
<image source="../drawable/map_cupboard_1.png" width="512" height="256"/>
|
||||
</tileset>
|
||||
<tileset firstgid="1585" name="map_curtain_1" tilewidth="32" tileheight="32">
|
||||
<tileset firstgid="1585" name="map_curtain_1" tilewidth="32" tileheight="32" tilecount="128" columns="16">
|
||||
<image source="../drawable/map_curtain_1.png" width="512" height="256"/>
|
||||
</tileset>
|
||||
<tileset firstgid="1713" name="map_entrance_1" tilewidth="32" tileheight="32">
|
||||
<tileset firstgid="1713" name="map_entrance_1" tilewidth="32" tileheight="32" tilecount="128" columns="16">
|
||||
<image source="../drawable/map_entrance_1.png" width="512" height="256"/>
|
||||
</tileset>
|
||||
<tileset firstgid="1841" name="map_entrance_2" tilewidth="32" tileheight="32">
|
||||
<tileset firstgid="1841" name="map_entrance_2" tilewidth="32" tileheight="32" tilecount="128" columns="16">
|
||||
<image source="../drawable/map_entrance_2.png" width="512" height="256"/>
|
||||
</tileset>
|
||||
<tileset firstgid="1969" name="map_fence_1" tilewidth="32" tileheight="32">
|
||||
<tileset firstgid="1969" name="map_fence_1" tilewidth="32" tileheight="32" tilecount="128" columns="16">
|
||||
<image source="../drawable/map_fence_1.png" width="512" height="256"/>
|
||||
</tileset>
|
||||
<tileset firstgid="2097" name="map_fence_2" tilewidth="32" tileheight="32">
|
||||
<tileset firstgid="2097" name="map_fence_2" tilewidth="32" tileheight="32" tilecount="128" columns="16">
|
||||
<image source="../drawable/map_fence_2.png" width="512" height="256"/>
|
||||
</tileset>
|
||||
<tileset firstgid="2225" name="map_fence_3" tilewidth="32" tileheight="32">
|
||||
<tileset firstgid="2225" name="map_fence_3" tilewidth="32" tileheight="32" tilecount="128" columns="16">
|
||||
<image source="../drawable/map_fence_3.png" width="512" height="256"/>
|
||||
</tileset>
|
||||
<tileset firstgid="2353" name="map_fence_4" tilewidth="32" tileheight="32">
|
||||
<tileset firstgid="2353" name="map_fence_4" tilewidth="32" tileheight="32" tilecount="128" columns="16">
|
||||
<image source="../drawable/map_fence_4.png" width="512" height="256"/>
|
||||
</tileset>
|
||||
<tileset firstgid="2481" name="map_ground_1" tilewidth="32" tileheight="32">
|
||||
<tileset firstgid="2481" name="map_ground_1" tilewidth="32" tileheight="32" tilecount="128" columns="16">
|
||||
<image source="../drawable/map_ground_1.png" width="512" height="256"/>
|
||||
</tileset>
|
||||
<tileset firstgid="2609" name="map_ground_2" tilewidth="32" tileheight="32">
|
||||
<tileset firstgid="2609" name="map_ground_2" tilewidth="32" tileheight="32" tilecount="128" columns="16">
|
||||
<image source="../drawable/map_ground_2.png" width="512" height="256"/>
|
||||
</tileset>
|
||||
<tileset firstgid="2737" name="map_ground_3" tilewidth="32" tileheight="32">
|
||||
<tileset firstgid="2737" name="map_ground_3" tilewidth="32" tileheight="32" tilecount="128" columns="16">
|
||||
<image source="../drawable/map_ground_3.png" width="512" height="256"/>
|
||||
</tileset>
|
||||
<tileset firstgid="2865" name="map_ground_4" tilewidth="32" tileheight="32">
|
||||
<tileset firstgid="2865" name="map_ground_4" tilewidth="32" tileheight="32" tilecount="128" columns="16">
|
||||
<image source="../drawable/map_ground_4.png" width="512" height="256"/>
|
||||
</tileset>
|
||||
<tileset firstgid="2993" name="map_ground_5" tilewidth="32" tileheight="32">
|
||||
<tileset firstgid="2993" name="map_ground_5" tilewidth="32" tileheight="32" tilecount="128" columns="16">
|
||||
<image source="../drawable/map_ground_5.png" width="512" height="256"/>
|
||||
</tileset>
|
||||
<tileset firstgid="3121" name="map_ground_6" tilewidth="32" tileheight="32">
|
||||
<tileset firstgid="3121" name="map_ground_6" tilewidth="32" tileheight="32" tilecount="128" columns="16">
|
||||
<image source="../drawable/map_ground_6.png" width="512" height="256"/>
|
||||
</tileset>
|
||||
<tileset firstgid="3249" name="map_ground_7" tilewidth="32" tileheight="32">
|
||||
<tileset firstgid="3249" name="map_ground_7" tilewidth="32" tileheight="32" tilecount="128" columns="16">
|
||||
<image source="../drawable/map_ground_7.png" width="512" height="256"/>
|
||||
</tileset>
|
||||
<tileset firstgid="3377" name="map_ground_8" tilewidth="32" tileheight="32">
|
||||
<tileset firstgid="3377" name="map_ground_8" tilewidth="32" tileheight="32" tilecount="128" columns="16">
|
||||
<image source="../drawable/map_ground_8.png" width="512" height="256"/>
|
||||
</tileset>
|
||||
<tileset firstgid="3505" name="map_house_1" tilewidth="32" tileheight="32">
|
||||
<tileset firstgid="3505" name="map_house_1" tilewidth="32" tileheight="32" tilecount="128" columns="16">
|
||||
<image source="../drawable/map_house_1.png" width="512" height="256"/>
|
||||
</tileset>
|
||||
<tileset firstgid="3633" name="map_house_2" tilewidth="32" tileheight="32">
|
||||
<tileset firstgid="3633" name="map_house_2" tilewidth="32" tileheight="32" tilecount="128" columns="16">
|
||||
<image source="../drawable/map_house_2.png" width="512" height="256"/>
|
||||
</tileset>
|
||||
<tileset firstgid="3761" name="map_indoor_1" tilewidth="32" tileheight="32">
|
||||
<tileset firstgid="3761" name="map_indoor_1" tilewidth="32" tileheight="32" tilecount="128" columns="16">
|
||||
<image source="../drawable/map_indoor_1.png" width="512" height="256"/>
|
||||
</tileset>
|
||||
<tileset firstgid="3889" name="map_indoor_2" tilewidth="32" tileheight="32">
|
||||
<tileset firstgid="3889" name="map_indoor_2" tilewidth="32" tileheight="32" tilecount="128" columns="16">
|
||||
<image source="../drawable/map_indoor_2.png" width="512" height="256"/>
|
||||
</tileset>
|
||||
<tileset firstgid="4017" name="map_kitchen_1" tilewidth="32" tileheight="32">
|
||||
<tileset firstgid="4017" name="map_kitchen_1" tilewidth="32" tileheight="32" tilecount="128" columns="16">
|
||||
<image source="../drawable/map_kitchen_1.png" width="512" height="256"/>
|
||||
</tileset>
|
||||
<tileset firstgid="4145" name="map_outdoor_1" tilewidth="32" tileheight="32">
|
||||
<tileset firstgid="4145" name="map_outdoor_1" tilewidth="32" tileheight="32" tilecount="128" columns="16">
|
||||
<image source="../drawable/map_outdoor_1.png" width="512" height="256"/>
|
||||
</tileset>
|
||||
<tileset firstgid="4273" name="map_pillar_1" tilewidth="32" tileheight="32">
|
||||
<tileset firstgid="4273" name="map_pillar_1" tilewidth="32" tileheight="32" tilecount="128" columns="16">
|
||||
<image source="../drawable/map_pillar_1.png" width="512" height="256"/>
|
||||
</tileset>
|
||||
<tileset firstgid="4401" name="map_pillar_2" tilewidth="32" tileheight="32">
|
||||
<tileset firstgid="4401" name="map_pillar_2" tilewidth="32" tileheight="32" tilecount="128" columns="16">
|
||||
<image source="../drawable/map_pillar_2.png" width="512" height="256"/>
|
||||
</tileset>
|
||||
<tileset firstgid="4529" name="map_plant_1" tilewidth="32" tileheight="32">
|
||||
<tileset firstgid="4529" name="map_plant_1" tilewidth="32" tileheight="32" tilecount="128" columns="16">
|
||||
<image source="../drawable/map_plant_1.png" width="512" height="256"/>
|
||||
</tileset>
|
||||
<tileset firstgid="4657" name="map_plant_2" tilewidth="32" tileheight="32">
|
||||
<tileset firstgid="4657" name="map_plant_2" tilewidth="32" tileheight="32" tilecount="128" columns="16">
|
||||
<image source="../drawable/map_plant_2.png" width="512" height="256"/>
|
||||
</tileset>
|
||||
<tileset firstgid="4785" name="map_rock_1" tilewidth="32" tileheight="32">
|
||||
<tileset firstgid="4785" name="map_rock_1" tilewidth="32" tileheight="32" tilecount="128" columns="16">
|
||||
<image source="../drawable/map_rock_1.png" width="512" height="256"/>
|
||||
</tileset>
|
||||
<tileset firstgid="4913" name="map_rock_2" tilewidth="32" tileheight="32">
|
||||
<tileset firstgid="4913" name="map_rock_2" tilewidth="32" tileheight="32" tilecount="128" columns="16">
|
||||
<image source="../drawable/map_rock_2.png" width="512" height="256"/>
|
||||
</tileset>
|
||||
<tileset firstgid="5041" name="map_roof_1" tilewidth="32" tileheight="32">
|
||||
<tileset firstgid="5041" name="map_roof_1" tilewidth="32" tileheight="32" tilecount="128" columns="16">
|
||||
<image source="../drawable/map_roof_1.png" width="512" height="256"/>
|
||||
</tileset>
|
||||
<tileset firstgid="5169" name="map_roof_2" tilewidth="32" tileheight="32">
|
||||
<tileset firstgid="5169" name="map_roof_2" tilewidth="32" tileheight="32" tilecount="128" columns="16">
|
||||
<image source="../drawable/map_roof_2.png" width="512" height="256"/>
|
||||
</tileset>
|
||||
<tileset firstgid="5297" name="map_roof_3" tilewidth="32" tileheight="32">
|
||||
<tileset firstgid="5297" name="map_roof_3" tilewidth="32" tileheight="32" tilecount="128" columns="16">
|
||||
<image source="../drawable/map_roof_3.png" width="512" height="256"/>
|
||||
</tileset>
|
||||
<tileset firstgid="5425" name="map_shop_1" tilewidth="32" tileheight="32">
|
||||
<tileset firstgid="5425" name="map_shop_1" tilewidth="32" tileheight="32" tilecount="128" columns="16">
|
||||
<image source="../drawable/map_shop_1.png" width="512" height="256"/>
|
||||
</tileset>
|
||||
<tileset firstgid="5553" name="map_sign_ladder_1" tilewidth="32" tileheight="32">
|
||||
<tileset firstgid="5553" name="map_sign_ladder_1" tilewidth="32" tileheight="32" tilecount="128" columns="16">
|
||||
<image source="../drawable/map_sign_ladder_1.png" width="512" height="256"/>
|
||||
</tileset>
|
||||
<tileset firstgid="5681" name="map_table_1" tilewidth="32" tileheight="32">
|
||||
<tileset firstgid="5681" name="map_table_1" tilewidth="32" tileheight="32" tilecount="128" columns="16">
|
||||
<image source="../drawable/map_table_1.png" width="512" height="256"/>
|
||||
</tileset>
|
||||
<tileset firstgid="5809" name="map_trail_1" tilewidth="32" tileheight="32">
|
||||
<tileset firstgid="5809" name="map_trail_1" tilewidth="32" tileheight="32" tilecount="128" columns="16">
|
||||
<image source="../drawable/map_trail_1.png" width="512" height="256"/>
|
||||
</tileset>
|
||||
<tileset firstgid="5937" name="map_transition_1" tilewidth="32" tileheight="32">
|
||||
<tileset firstgid="5937" name="map_transition_1" tilewidth="32" tileheight="32" tilecount="128" columns="16">
|
||||
<image source="../drawable/map_transition_1.png" width="512" height="256"/>
|
||||
</tileset>
|
||||
<tileset firstgid="6065" name="map_transition_2" tilewidth="32" tileheight="32">
|
||||
<tileset firstgid="6065" name="map_transition_2" tilewidth="32" tileheight="32" tilecount="128" columns="16">
|
||||
<image source="../drawable/map_transition_2.png" width="512" height="256"/>
|
||||
</tileset>
|
||||
<tileset firstgid="6193" name="map_transition_3" tilewidth="32" tileheight="32">
|
||||
<tileset firstgid="6193" name="map_transition_3" tilewidth="32" tileheight="32" tilecount="128" columns="16">
|
||||
<image source="../drawable/map_transition_3.png" width="512" height="256"/>
|
||||
</tileset>
|
||||
<tileset firstgid="6321" name="map_transition_4" tilewidth="32" tileheight="32">
|
||||
<tileset firstgid="6321" name="map_transition_4" tilewidth="32" tileheight="32" tilecount="128" columns="16">
|
||||
<image source="../drawable/map_transition_4.png" width="512" height="256"/>
|
||||
</tileset>
|
||||
<tileset firstgid="6449" name="map_transition_5" tilewidth="32" tileheight="32">
|
||||
<tileset firstgid="6449" name="map_transition_5" tilewidth="32" tileheight="32" tilecount="128" columns="16">
|
||||
<image source="../drawable/map_transition_5.png" width="512" height="256"/>
|
||||
</tileset>
|
||||
<tileset firstgid="6577" name="map_tree_1" tilewidth="32" tileheight="32">
|
||||
<tileset firstgid="6577" name="map_tree_1" tilewidth="32" tileheight="32" tilecount="128" columns="16">
|
||||
<image source="../drawable/map_tree_1.png" width="512" height="256"/>
|
||||
</tileset>
|
||||
<tileset firstgid="6705" name="map_tree_2" tilewidth="32" tileheight="32">
|
||||
<tileset firstgid="6705" name="map_tree_2" tilewidth="32" tileheight="32" tilecount="128" columns="16">
|
||||
<image source="../drawable/map_tree_2.png" width="512" height="256"/>
|
||||
</tileset>
|
||||
<tileset firstgid="6833" name="map_wall_1" tilewidth="32" tileheight="32">
|
||||
<tileset firstgid="6833" name="map_wall_1" tilewidth="32" tileheight="32" tilecount="128" columns="16">
|
||||
<image source="../drawable/map_wall_1.png" width="512" height="256"/>
|
||||
</tileset>
|
||||
<tileset firstgid="6961" name="map_wall_2" tilewidth="32" tileheight="32">
|
||||
<tileset firstgid="6961" name="map_wall_2" tilewidth="32" tileheight="32" tilecount="120" columns="15">
|
||||
<image source="../drawable/map_wall_2.png" width="480" height="256"/>
|
||||
</tileset>
|
||||
<tileset firstgid="7081" name="map_wall_3" tilewidth="32" tileheight="32">
|
||||
<tileset firstgid="7081" name="map_wall_3" tilewidth="32" tileheight="32" tilecount="120" columns="15">
|
||||
<image source="../drawable/map_wall_3.png" width="480" height="256"/>
|
||||
</tileset>
|
||||
<tileset firstgid="7201" name="map_wall_4" tilewidth="32" tileheight="32">
|
||||
<tileset firstgid="7201" name="map_wall_4" tilewidth="32" tileheight="32" tilecount="120" columns="15">
|
||||
<image source="../drawable/map_wall_4.png" width="480" height="256"/>
|
||||
</tileset>
|
||||
<tileset firstgid="7321" name="map_window_1" tilewidth="32" tileheight="32">
|
||||
<tileset firstgid="7321" name="map_window_1" tilewidth="32" tileheight="32" tilecount="128" columns="16">
|
||||
<image source="../drawable/map_window_1.png" width="512" height="256"/>
|
||||
</tileset>
|
||||
<tileset firstgid="7449" name="map_window_2" tilewidth="32" tileheight="32">
|
||||
<tileset firstgid="7449" name="map_window_2" tilewidth="32" tileheight="32" tilecount="128" columns="16">
|
||||
<image source="../drawable/map_window_2.png" width="512" height="256"/>
|
||||
</tileset>
|
||||
<layer name="Ground" width="21" height="30">
|
||||
@@ -192,7 +191,7 @@
|
||||
</layer>
|
||||
<layer name="Objects" width="21" height="30">
|
||||
<data encoding="base64" compression="zlib">
|
||||
eJytVU1rGzEQFb0JfLAWEnCPPfTcOP0DLvkDCfkzbWnvJST3fP6C5vPWYxOo7XOgDmu70B6CIR89tddWD81Ds7J2QyAPxGhXo9n3ZkbaSceYH37cN1hguGjMP9fseye+tw/43IoduLwvffhtYNIQ76sf5+KLmOSg49An5an50I5dGB9axvxph5h/vf3YimvpHvCbdkKO3nq/dw3jsh2+D1vn874VuSPuJ//8S3i/fB7szEW9BN71rDFdP5b9uPB7lrz96e1GK+bxTmICB4UxpYtz4MoF7cBvb1dsXBu6MMe7jQzPvgv9Am7QiHyBR084AeC0ZoMfgfmqxDxVuSVP4JuP9V1pXrfVuhPQc63eISZ7YJpoR26QW+oj+IzYx0X8Bt/n8jlQ2qkJeG2rz3XzXD41Zi5yWpU6d23UgPyyv5ZkrY7nfkYTsVeE+Gu2uvbC1fM88X6H4jt2VX3siTLJS6o95dlNeoZ631iTBWo+cqFPkIe6fELTjatqWpfcIS/sWd0Dew11r9NEHBbVNZ6Nz8LjobproJfSfidH2oFrPu8E5j2pM5+hHbXcT/yovY4nexBYkVyOpO68kzTwnjUqXfW8d+38AEfkqq/q9Ur6VPcIeabnHd+ijhupp87Zsao170TOdT6nmfNOoJ5Xsq90jzvvZ7qXhNdM1fmyHfnqs3/RmdfOup8rngeJPgD/qi0/NuWfw1qX6myMG/qTvazzwLXOs7APa0fF/J2Y68+R0ttXc6wtqLuH3wTSez7libzl7u9tv7YjY1d6kD1TSo5wDlKe3PdlMe4fqnnT4J7dhOfkCS14/gfUNXdi
|
||||
eJytVU1rFEEQbbw17GF7wMB69OBZR//ASv5AQv6Mit5D0Lvm4xcYo948moC7e15ww+yuoAdZSKInvWo/uh5d09s9QbCg6a/qmvdeVfcsBsZ88e1HRw+bbBjzx3X7Xonv5TU+l9KPXd6XPvw2bNER76Nvp+KLmMSg49AnxanxsJ/7GE97xvzqx5i//fhZL+zN3foZ4FsOgkaPvN/jQkut5PekF7Ej7q6ffxPcd26FfuUiXxrWhtaY2rf7vp35M/d8/9X3e72o45XE/Ol5HVXGNBIHY9i5i/zhs2nj3sSFMdb2MjhHLtQLsE37QS/gGAomGDBt2+BHw3hLYr5T2u4q3T75WJ8V5x3bzjsNfL6rNcRkDSxVTPCANtCW/GicI/ZJFb/B9ZyeY8WdnGAPbHteGuf01LZyEdOW5Lm2kQP0nfajxrUt4zzMcKIdVCH+tm3v3XZlnG+937H4zl2bH2uiSXRJuac466RmyPehNVlDzmcu1Al0KOkJTheuzWlHtIMurFldAwcdeS9xoh1X7T3ejdeC47q8a0MtpfVOjOzHroxT5xPjoeSZc3BHLg8TP3Iv4WQNwjZFy5nknW+SNqwzR41r3/farjdghFYjla+7Uqe6Rogzve/TfuRxIfnUmp2oXPNN5FjruczcdxryeS7nGvdv9/29riXBtVJ5Bn7i1Xf/bLDOnXk/VTiPEn4w/Kte+PZc/jnMdaPuxryjPlnLWgfuDW6Ec9h7U62/ibn6nCm+IzXG3k319vCbsPSdT3FCt9z7/dLvvZK2LzXImmlEI9yDFCfPfdiI5ydq3NV4Zj/BufiPPXD+BVf1dSk=
|
||||
</data>
|
||||
</layer>
|
||||
<layer name="Layer1" width="21" height="30" visible="0">
|
||||
@@ -202,33 +201,33 @@
|
||||
</layer>
|
||||
<layer name="Above" width="21" height="30">
|
||||
<data encoding="base64" compression="zlib">
|
||||
eJzFlssNwjAMhi0kDkgcCheUOZiAigVgPC4wAtBJ4ByQQGrnoBaN5KZO4iRFfJeUYP/xI64KAPBQAFr1V4r5rVV/z+fj4tLaXS1brdw2Ul2kLr5rUwz/M3G6zgyxmoRtnp3mrV3v3XMVcU7F+BteAZ2ayZlSzgDewljsmE3ukhqMAcaK2PcE4Wpjc1wO97adpt33nJyMZiy+HFI1sWYbh++e2T8xNaKM1esqcC99uPI5M7FL54yrb26uqT3znRujKa0x1ZTMUaymhNJhT9/5O4EmN+OhM1LBPqX2GKH9ofc0R5POwJrocLP+D6aLdF9fbyn2t4R0DsZ6tx3m/LPU55d8ADDDO+s=
|
||||
eJzFlksOwiAQhicmLkxcVDeGc3gCGy+gx3OjR1A5ia7RRJP2HJYE4pQOMECN36aIMz/zYJoCADwEgBL9J8b+VqK/F/Lxcensro6tEn4brm5TfddtNfzfxuk7M8ZqErd5Gs1b97ybtUw4RxL+lldEpyFyxtQzgDczFjdmmzunBmOgY9W490RD1cbluBzubY2m2/eSnKxmKqEccjV1zTYe3z2xfyJqhBmr1zJyL0P48jkTsXPnjKpvaa65PQudm6LJrTHW5MxRqiaH2mOP3/k7hiY147EzctF9yu2xBvcH39MSTTwDa6RDzfo/mC7yfUO9xbjfEtw5GOvddpjTa67PL/kANJc76w==
|
||||
</data>
|
||||
</layer>
|
||||
<layer name="Walkable" width="21" height="30" visible="0">
|
||||
<layer name="Walkable" width="21" height="30">
|
||||
<data encoding="base64" compression="zlib">
|
||||
eJzVk1EOwCAIQz3F7n8Fb7gvE7MAfUV/RkJmXK0t4HzGmCJXKNzCEhzFundTvIP5fm9kl2vXksUJX7R2+6G07PtUe+WVBO1Bxq3qQnV2eudg6XxV/qKzxHvFR8L10+XLvFNPTo+UvkorOaf4iXdSY+K9et/VG3MyqgOdeTWj2T+qxw2Xs9JEdGb9VHunOh3/CtvhpLMc3fPXfAGBeSqQ
|
||||
eJzVk8ENwCAMA5mi+6/Ahn0h9UHsM1EfICFVYMw5pPMZY5q5htMtLdFRbXo31aeeNFPC2PFVo+O3+07r4Vi+65RdZSWD9kDl7eryNyfV0v5W+XZnSXbld5qdvlXiV2WnmdL/UfEpVnLO+ZPspMYkO91zjK4PKibqV9Wx2qM86Ug9FRPhrN7TrXU5k/xOe+JJe3l3z63zBeTIKpA=
|
||||
</data>
|
||||
</layer>
|
||||
<layer name="Layer2" width="21" height="30" visible="0">
|
||||
<data encoding="base64" compression="zlib">
|
||||
eJzNUlsKwDAI6yl2/yv0hvsqDIkmcTImyB6kqUnc11qb9CmGO1gFp2Ldu1W8g4nPie5yPWfJ6g0fenfzYH51OTOtSqkZZNzMF+Znx2tFe3e/qlkqXxh3PB85Xe1qVo4/7v0KrtKH5kL4L3ceYdAZNLOza4zT7cxHZYcyTehbnRPxTHAqXGoGbOfZvwlOpMPVrvqt5l55yLj+3jfjIT3/
|
||||
eJzNklEKwCAMQz3F7n8Fb7gvfyRtXlDGhMIc8dnEzmeMaWotp1taoqPa9G6qT5nUU9LjCbdbJzz1neZRna2yp8zKK1l0Biq2y0V537UnTOqJznfXS5eLY+/nd2bqnb5Vkk96P9F1/lRfSv/lzCuNOqN6TmbNMdOqciQzVHlSe9qn4txgEhZ9Azfz7t8NpvKReqd503fvMnSsv9cLhdk9/w==
|
||||
</data>
|
||||
</layer>
|
||||
<objectgroup name="Mapevents">
|
||||
<object name="north" type="mapchange" x="288" y="0" width="64" height="32">
|
||||
<object id="1" name="north" type="mapchange" x="288" y="0" width="64" height="32">
|
||||
<properties>
|
||||
<property name="map" value="graveyard0"/>
|
||||
<property name="place" value="south"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object name="east" type="mapchange" x="640" y="32" width="32" height="64">
|
||||
<object id="2" name="east" type="mapchange" x="640" y="32" width="32" height="64">
|
||||
<properties>
|
||||
<property name="map" value="waterway5"/>
|
||||
<property name="place" value="west"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object name="north2" type="mapchange" x="640" y="0" width="32" height="32">
|
||||
<object id="3" name="north2" type="mapchange" x="640" y="0" width="32" height="32">
|
||||
<properties>
|
||||
<property name="map" value="waterway4"/>
|
||||
<property name="place" value="south3"/>
|
||||
@@ -239,121 +238,121 @@
|
||||
<properties>
|
||||
<property name="active" value="false"/>
|
||||
</properties>
|
||||
<object name="graveyard_corpse_0" type="spawn" x="64" y="192" width="224" height="224">
|
||||
<object id="4" name="graveyard_corpse_0" type="spawn" x="64" y="192" width="224" height="224">
|
||||
<properties>
|
||||
<property name="active" value="false"/>
|
||||
<property name="quantity" value="2"/>
|
||||
<property name="spawngroup" value="graveyard_corpse"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object name="graveyardking" type="spawn" x="320" y="832" width="32" height="32">
|
||||
<object id="5" name="graveyardking" type="spawn" x="320" y="832" width="32" height="32">
|
||||
<properties>
|
||||
<property name="spawngroup" value="graveyardking"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object name="graveyard_corpse_1" type="spawn" x="64" y="416" width="224" height="224">
|
||||
<object id="6" name="graveyard_corpse_1" type="spawn" x="64" y="416" width="224" height="224">
|
||||
<properties>
|
||||
<property name="active" value="false"/>
|
||||
<property name="spawngroup" value="graveyard_corpse"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object name="graveyard_corpse_2" type="spawn" x="64" y="640" width="256" height="128">
|
||||
<object id="7" name="graveyard_corpse_2" type="spawn" x="64" y="640" width="256" height="128">
|
||||
<properties>
|
||||
<property name="active" value="false"/>
|
||||
<property name="quantity" value="2"/>
|
||||
<property name="spawngroup" value="graveyard_corpse"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object name="graveyard_corpse2_0" type="spawn" x="192" y="320" width="32" height="32">
|
||||
<object id="8" name="graveyard_corpse2_0" type="spawn" x="192" y="320" width="32" height="32">
|
||||
<properties>
|
||||
<property name="active" value="false"/>
|
||||
<property name="spawngroup" value="graveyard_corpse2"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object name="graveyard_corpse2_1" type="spawn" x="192" y="512" width="32" height="32">
|
||||
<object id="9" name="graveyard_corpse2_1" type="spawn" x="192" y="512" width="32" height="32">
|
||||
<properties>
|
||||
<property name="active" value="false"/>
|
||||
<property name="spawngroup" value="graveyard_corpse2"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object name="graveyard_corpse2_2" type="spawn" x="320" y="704" width="32" height="32">
|
||||
<object id="10" name="graveyard_corpse2_2" type="spawn" x="320" y="704" width="32" height="32">
|
||||
<properties>
|
||||
<property name="active" value="false"/>
|
||||
<property name="spawngroup" value="graveyard_corpse2"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object name="graveyard_corpse_3" type="spawn" x="288" y="192" width="128" height="224">
|
||||
<object id="11" name="graveyard_corpse_3" type="spawn" x="288" y="192" width="128" height="224">
|
||||
<properties>
|
||||
<property name="active" value="false"/>
|
||||
<property name="quantity" value="2"/>
|
||||
<property name="spawngroup" value="graveyard_corpse"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object name="graveyard_corpse_4" type="spawn" x="416" y="192" width="160" height="224">
|
||||
<object id="12" name="graveyard_corpse_4" type="spawn" x="416" y="192" width="160" height="224">
|
||||
<properties>
|
||||
<property name="active" value="false"/>
|
||||
<property name="quantity" value="2"/>
|
||||
<property name="spawngroup" value="graveyard_corpse"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object name="graveyard_corpse_5" type="spawn" x="288" y="416" width="160" height="224">
|
||||
<object id="13" name="graveyard_corpse_5" type="spawn" x="288" y="416" width="160" height="224">
|
||||
<properties>
|
||||
<property name="active" value="false"/>
|
||||
<property name="quantity" value="4"/>
|
||||
<property name="spawngroup" value="graveyard_corpse"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object name="graveyard_corpse_6" type="spawn" x="448" y="416" width="128" height="224">
|
||||
<object id="14" name="graveyard_corpse_6" type="spawn" x="448" y="416" width="128" height="224">
|
||||
<properties>
|
||||
<property name="active" value="false"/>
|
||||
<property name="spawngroup" value="graveyard_corpse"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object name="graveyard_corpse_7" type="spawn" x="320" y="640" width="256" height="128">
|
||||
<object id="15" name="graveyard_corpse_7" type="spawn" x="320" y="640" width="256" height="128">
|
||||
<properties>
|
||||
<property name="active" value="false"/>
|
||||
<property name="quantity" value="2"/>
|
||||
<property name="spawngroup" value="graveyard_corpse"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object name="graveyard_corpse_8" type="spawn" x="384" y="768" width="192" height="96">
|
||||
<object id="16" name="graveyard_corpse_8" type="spawn" x="384" y="768" width="192" height="96">
|
||||
<properties>
|
||||
<property name="active" value="false"/>
|
||||
<property name="spawngroup" value="graveyard_corpse"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object name="graveyard_corpse_9" type="spawn" x="64" y="768" width="192" height="96">
|
||||
<object id="17" name="graveyard_corpse_9" type="spawn" x="64" y="768" width="192" height="96">
|
||||
<properties>
|
||||
<property name="active" value="false"/>
|
||||
<property name="spawngroup" value="graveyard_corpse"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object name="graveyard_corpse2_3" type="spawn" x="416" y="512" width="32" height="32">
|
||||
<object id="18" name="graveyard_corpse2_3" type="spawn" x="416" y="512" width="32" height="32">
|
||||
<properties>
|
||||
<property name="active" value="false"/>
|
||||
<property name="spawngroup" value="graveyard_corpse2"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object name="graveyard_corpse2_4" type="spawn" x="416" y="704" width="32" height="32">
|
||||
<object id="19" name="graveyard_corpse2_4" type="spawn" x="416" y="704" width="32" height="32">
|
||||
<properties>
|
||||
<property name="active" value="false"/>
|
||||
<property name="spawngroup" value="graveyard_corpse2"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object name="graveyard_corpse2_5" type="spawn" x="416" y="320" width="32" height="32">
|
||||
<object id="20" name="graveyard_corpse2_5" type="spawn" x="416" y="320" width="32" height="32">
|
||||
<properties>
|
||||
<property name="active" value="false"/>
|
||||
<property name="spawngroup" value="graveyard_corpse2"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object name="graveyard_corpse_entrance" type="spawn" x="224" y="160" width="160" height="64">
|
||||
<object id="21" name="graveyard_corpse_entrance" type="spawn" x="224" y="160" width="160" height="64">
|
||||
<properties>
|
||||
<property name="active" value="false"/>
|
||||
<property name="quantity" value="2"/>
|
||||
<property name="spawngroup" value="graveyard_corpse"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object name="graveyard_corpse_boss_patrol" type="spawn" x="256" y="704" width="128" height="96">
|
||||
<object id="22" name="graveyard_corpse_boss_patrol" type="spawn" x="256" y="704" width="128" height="96">
|
||||
<properties>
|
||||
<property name="active" value="false"/>
|
||||
<property name="quantity" value="2"/>
|
||||
@@ -362,7 +361,7 @@
|
||||
</object>
|
||||
</objectgroup>
|
||||
<objectgroup name="Keys">
|
||||
<object name="graveyardenterance" type="key" x="320" y="96" width="32" height="32">
|
||||
<object id="23" name="graveyardenterance" type="key" x="288" y="96" width="64" height="32">
|
||||
<properties>
|
||||
<property name="phrase" value="graveyardwall_1"/>
|
||||
<property name="requireId" value="graveyard_quest"/>
|
||||
@@ -372,169 +371,169 @@
|
||||
</object>
|
||||
</objectgroup>
|
||||
<objectgroup name="Script">
|
||||
<object name="graveyardday" type="script" x="256" y="768" width="128" height="64">
|
||||
<object id="24" name="graveyardday" type="script" x="256" y="768" width="128" height="64">
|
||||
<properties>
|
||||
<property name="when" value="always"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object name="graveyardbosskill_10" type="script" x="288" y="800" width="64" height="64">
|
||||
<object id="25" name="graveyardbosskill_10" type="script" x="288" y="800" width="64" height="64">
|
||||
<properties>
|
||||
<property name="when" value="always"/>
|
||||
</properties>
|
||||
</object>
|
||||
</objectgroup>
|
||||
<objectgroup name="Replace" visible="0">
|
||||
<object name="graveyard_quest:50" type="replace" x="96" y="224" width="32" height="32">
|
||||
<object id="26" name="graveyard_quest:50" type="replace" x="96" y="224" width="32" height="32">
|
||||
<properties>
|
||||
<property name="Objects" value="Layer1"/>
|
||||
<property name="Walkable" value="Layer2"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object name="graveyard_quest:50" type="replace" x="416" y="224" width="32" height="32">
|
||||
<object id="27" name="graveyard_quest:50" type="replace" x="416" y="224" width="32" height="32">
|
||||
<properties>
|
||||
<property name="Objects" value="Layer1"/>
|
||||
<property name="Walkable" value="Layer2"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object name="graveyard_quest:50" type="replace" x="512" y="224" width="32" height="32">
|
||||
<object id="28" name="graveyard_quest:50" type="replace" x="512" y="224" width="32" height="32">
|
||||
<properties>
|
||||
<property name="Objects" value="Layer1"/>
|
||||
<property name="Walkable" value="Layer2"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object name="graveyard_quest:50" type="replace" x="96" y="320" width="32" height="32">
|
||||
<object id="29" name="graveyard_quest:50" type="replace" x="96" y="320" width="32" height="32">
|
||||
<properties>
|
||||
<property name="Objects" value="Layer1"/>
|
||||
<property name="Walkable" value="Layer2"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object name="graveyard_quest:50" type="replace" x="192" y="320" width="32" height="32">
|
||||
<object id="30" name="graveyard_quest:50" type="replace" x="192" y="320" width="32" height="32">
|
||||
<properties>
|
||||
<property name="Objects" value="Layer1"/>
|
||||
<property name="Walkable" value="Layer2"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object name="graveyard_quest:50" type="replace" x="320" y="320" width="32" height="32">
|
||||
<object id="31" name="graveyard_quest:50" type="replace" x="320" y="320" width="32" height="32">
|
||||
<properties>
|
||||
<property name="Objects" value="Layer1"/>
|
||||
<property name="Walkable" value="Layer2"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object name="graveyard_quest:50" type="replace" x="416" y="320" width="32" height="32">
|
||||
<object id="32" name="graveyard_quest:50" type="replace" x="416" y="320" width="32" height="32">
|
||||
<properties>
|
||||
<property name="Objects" value="Layer1"/>
|
||||
<property name="Walkable" value="Layer2"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object name="graveyard_quest:50" type="replace" x="512" y="320" width="32" height="32">
|
||||
<object id="33" name="graveyard_quest:50" type="replace" x="512" y="320" width="32" height="32">
|
||||
<properties>
|
||||
<property name="Objects" value="Layer1"/>
|
||||
<property name="Walkable" value="Layer2"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object name="graveyard_quest:50" type="replace" x="192" y="416" width="32" height="32">
|
||||
<object id="34" name="graveyard_quest:50" type="replace" x="192" y="416" width="32" height="32">
|
||||
<properties>
|
||||
<property name="Objects" value="Layer1"/>
|
||||
<property name="Walkable" value="Layer2"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object name="graveyard_quest:50" type="replace" x="320" y="416" width="32" height="32">
|
||||
<object id="35" name="graveyard_quest:50" type="replace" x="320" y="416" width="32" height="32">
|
||||
<properties>
|
||||
<property name="Objects" value="Layer1"/>
|
||||
<property name="Walkable" value="Layer2"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object name="graveyard_quest:50" type="replace" x="416" y="416" width="32" height="32">
|
||||
<object id="36" name="graveyard_quest:50" type="replace" x="416" y="416" width="32" height="32">
|
||||
<properties>
|
||||
<property name="Objects" value="Layer1"/>
|
||||
<property name="Walkable" value="Layer2"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object name="graveyard_quest:50" type="replace" x="512" y="416" width="32" height="32">
|
||||
<object id="37" name="graveyard_quest:50" type="replace" x="512" y="416" width="32" height="32">
|
||||
<properties>
|
||||
<property name="Objects" value="Layer1"/>
|
||||
<property name="Walkable" value="Layer2"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object name="graveyard_quest:50" type="replace" x="96" y="512" width="32" height="32">
|
||||
<object id="38" name="graveyard_quest:50" type="replace" x="96" y="512" width="32" height="32">
|
||||
<properties>
|
||||
<property name="Objects" value="Layer1"/>
|
||||
<property name="Walkable" value="Layer2"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object name="graveyard_quest:50" type="replace" x="192" y="512" width="32" height="32">
|
||||
<object id="39" name="graveyard_quest:50" type="replace" x="192" y="512" width="32" height="32">
|
||||
<properties>
|
||||
<property name="Objects" value="Layer1"/>
|
||||
<property name="Walkable" value="Layer2"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object name="graveyard_quest:50" type="replace" x="416" y="512" width="32" height="32">
|
||||
<object id="40" name="graveyard_quest:50" type="replace" x="416" y="512" width="32" height="32">
|
||||
<properties>
|
||||
<property name="Objects" value="Layer1"/>
|
||||
<property name="Walkable" value="Layer2"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object name="graveyard_quest:50" type="replace" x="96" y="608" width="32" height="32">
|
||||
<object id="41" name="graveyard_quest:50" type="replace" x="96" y="608" width="32" height="32">
|
||||
<properties>
|
||||
<property name="Objects" value="Layer1"/>
|
||||
<property name="Walkable" value="Layer2"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object name="graveyard_quest:50" type="replace" x="192" y="608" width="32" height="32">
|
||||
<object id="42" name="graveyard_quest:50" type="replace" x="192" y="608" width="32" height="32">
|
||||
<properties>
|
||||
<property name="Objects" value="Layer1"/>
|
||||
<property name="Walkable" value="Layer2"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object name="graveyard_quest:50" type="replace" x="320" y="608" width="32" height="32">
|
||||
<object id="43" name="graveyard_quest:50" type="replace" x="320" y="608" width="32" height="32">
|
||||
<properties>
|
||||
<property name="Objects" value="Layer1"/>
|
||||
<property name="Walkable" value="Layer2"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object name="graveyard_quest:50" type="replace" x="512" y="608" width="32" height="32">
|
||||
<object id="44" name="graveyard_quest:50" type="replace" x="512" y="608" width="32" height="32">
|
||||
<properties>
|
||||
<property name="Objects" value="Layer1"/>
|
||||
<property name="Walkable" value="Layer2"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object name="graveyard_quest:50" type="replace" x="96" y="704" width="32" height="32">
|
||||
<object id="45" name="graveyard_quest:50" type="replace" x="96" y="704" width="32" height="32">
|
||||
<properties>
|
||||
<property name="Objects" value="Layer1"/>
|
||||
<property name="Walkable" value="Layer2"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object name="graveyard_quest:50" type="replace" x="320" y="704" width="32" height="32">
|
||||
<object id="46" name="graveyard_quest:50" type="replace" x="320" y="704" width="32" height="32">
|
||||
<properties>
|
||||
<property name="Objects" value="Layer1"/>
|
||||
<property name="Walkable" value="Layer2"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object name="graveyard_quest:50" type="replace" x="416" y="704" width="32" height="32">
|
||||
<object id="47" name="graveyard_quest:50" type="replace" x="416" y="704" width="32" height="32">
|
||||
<properties>
|
||||
<property name="Objects" value="Layer1"/>
|
||||
<property name="Walkable" value="Layer2"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object name="graveyard_quest:50" type="replace" x="512" y="704" width="32" height="32">
|
||||
<object id="48" name="graveyard_quest:50" type="replace" x="512" y="704" width="32" height="32">
|
||||
<properties>
|
||||
<property name="Objects" value="Layer1"/>
|
||||
<property name="Walkable" value="Layer2"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object name="graveyard_quest:50" type="replace" x="512" y="800" width="32" height="32">
|
||||
<object id="49" name="graveyard_quest:50" type="replace" x="512" y="800" width="32" height="32">
|
||||
<properties>
|
||||
<property name="Objects" value="Layer1"/>
|
||||
<property name="Walkable" value="Layer2"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object name="graveyard_quest:50" type="replace" x="96" y="800" width="32" height="32">
|
||||
<object id="50" name="graveyard_quest:50" type="replace" x="96" y="800" width="32" height="32">
|
||||
<properties>
|
||||
<property name="Objects" value="Layer1"/>
|
||||
<property name="Walkable" value="Layer2"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object name="graveyard_quest:50" type="replace" x="192" y="800" width="32" height="32">
|
||||
<object id="51" name="graveyard_quest:50" type="replace" x="192" y="800" width="32" height="32">
|
||||
<properties>
|
||||
<property name="Objects" value="Layer1"/>
|
||||
<property name="Walkable" value="Layer2"/>
|
||||
|
||||
@@ -3,12 +3,13 @@ package com.gpl.rpg.AndorsTrail;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Locale;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.Resources;
|
||||
import android.os.Build;
|
||||
import android.os.Environment;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
@@ -16,6 +17,7 @@ import android.view.WindowManager;
|
||||
import com.gpl.rpg.AndorsTrail.context.ControllerContext;
|
||||
import com.gpl.rpg.AndorsTrail.context.WorldContext;
|
||||
import com.gpl.rpg.AndorsTrail.controller.Constants;
|
||||
import com.gpl.rpg.AndorsTrail.util.L;
|
||||
|
||||
public final class AndorsTrailApplication extends Application {
|
||||
|
||||
@@ -32,9 +34,9 @@ public final class AndorsTrailApplication extends Application {
|
||||
public static final boolean IS_RELEASE_VERSION = !CURRENT_VERSION_DISPLAY.matches(".*[a-d].*");
|
||||
|
||||
private final AndorsTrailPreferences preferences = new AndorsTrailPreferences();
|
||||
private final WorldContext world = new WorldContext();
|
||||
private final ControllerContext controllers = new ControllerContext(this, world);
|
||||
private final WorldSetup setup = new WorldSetup(world, controllers, this);
|
||||
private WorldContext world = new WorldContext();
|
||||
private ControllerContext controllers = new ControllerContext(this, world);
|
||||
private WorldSetup setup = new WorldSetup(world, controllers, this);
|
||||
public WorldContext getWorld() { return world; }
|
||||
public WorldSetup getWorldSetup() { return setup; }
|
||||
public AndorsTrailPreferences getPreferences() { return preferences; }
|
||||
@@ -62,15 +64,23 @@ public final class AndorsTrailApplication extends Application {
|
||||
setLocale(activity);
|
||||
}
|
||||
|
||||
//Get default locale at startup, as somehow it seems that changing the app's
|
||||
//configured locale impacts the value returned by Locale.getDefault() nowadays.
|
||||
private final Locale defaultLocale = Locale.getDefault();
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
public boolean setLocale(Activity context) {
|
||||
Resources res = context.getResources();
|
||||
Configuration conf = res.getConfiguration();
|
||||
final Locale targetLocale = preferences.useLocalizedResources ? Locale.getDefault() : Locale.US;
|
||||
if (targetLocale.equals(conf.locale)) return false;
|
||||
final Locale targetLocale = preferences.useLocalizedResources ? defaultLocale : Locale.US;
|
||||
if (targetLocale.equals(conf.locale)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
conf.locale = targetLocale;
|
||||
res.updateConfiguration(conf, res.getDisplayMetrics());
|
||||
this.getResources().updateConfiguration(conf, res.getDisplayMetrics());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -127,4 +137,9 @@ public final class AndorsTrailApplication extends Application {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public void discardWorld() {
|
||||
world = new WorldContext();
|
||||
controllers = new ControllerContext(this, world);
|
||||
setup = new WorldSetup(world, controllers, getApplicationContext());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
package com.gpl.rpg.AndorsTrail.activity.fragment;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.SharedPreferences.Editor;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.view.LayoutInflater;
|
||||
@@ -28,6 +30,7 @@ import com.gpl.rpg.AndorsTrail.controller.Constants;
|
||||
import com.gpl.rpg.AndorsTrail.resource.tiles.TileManager;
|
||||
import com.gpl.rpg.AndorsTrail.savegames.Savegames;
|
||||
import com.gpl.rpg.AndorsTrail.savegames.Savegames.FileHeader;
|
||||
import com.gpl.rpg.AndorsTrail.util.L;
|
||||
import com.gpl.rpg.AndorsTrail.util.ThemeHelper;
|
||||
import com.gpl.rpg.AndorsTrail.view.CustomDialogFactory;
|
||||
|
||||
@@ -259,18 +262,25 @@ public class StartScreenActivity_MainMenu extends Fragment {
|
||||
// Changing the locale after having loaded the game requires resources to
|
||||
// be re-loaded. Therefore, we just exit here.
|
||||
Toast.makeText(getActivity(), R.string.change_locale_requires_restart, Toast.LENGTH_LONG).show();
|
||||
getActivity().finish();
|
||||
doFinish();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (ThemeHelper.changeTheme(preferences.selectedTheme)) {
|
||||
// Changing the theme requires a restart to re-create all activities.
|
||||
Toast.makeText(getActivity(), R.string.change_theme_requires_restart, Toast.LENGTH_LONG).show();
|
||||
getActivity().finish();
|
||||
doFinish();
|
||||
return;
|
||||
}
|
||||
app.getWorld().tileManager.updatePreferences(preferences);
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
private void doFinish() {
|
||||
//For Lollipop and above
|
||||
((AndorsTrailApplication)getActivity().getApplication()).discardWorld();
|
||||
getActivity().finish();
|
||||
}
|
||||
|
||||
|
||||
public interface OnNewGameRequestedListener {
|
||||
|
||||
@@ -1,317 +1,318 @@
|
||||
package com.gpl.rpg.AndorsTrail.controller;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Bitmap.Config;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Environment;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
|
||||
import com.gpl.rpg.AndorsTrail.R;
|
||||
import com.gpl.rpg.AndorsTrail.activity.DisplayWorldMapActivity;
|
||||
import com.gpl.rpg.AndorsTrail.context.WorldContext;
|
||||
import com.gpl.rpg.AndorsTrail.model.map.LayeredTileMap;
|
||||
import com.gpl.rpg.AndorsTrail.model.map.MapLayer;
|
||||
import com.gpl.rpg.AndorsTrail.model.map.PredefinedMap;
|
||||
import com.gpl.rpg.AndorsTrail.model.map.WorldMapSegment;
|
||||
import com.gpl.rpg.AndorsTrail.model.map.WorldMapSegment.NamedWorldMapArea;
|
||||
import com.gpl.rpg.AndorsTrail.model.map.WorldMapSegment.WorldMapSegmentMap;
|
||||
import com.gpl.rpg.AndorsTrail.resource.tiles.TileCollection;
|
||||
import com.gpl.rpg.AndorsTrail.util.Coord;
|
||||
import com.gpl.rpg.AndorsTrail.util.CoordRect;
|
||||
import com.gpl.rpg.AndorsTrail.util.L;
|
||||
import com.gpl.rpg.AndorsTrail.util.Size;
|
||||
|
||||
public final class WorldMapController {
|
||||
|
||||
private static final int WORLDMAP_SCREENSHOT_TILESIZE = 8;
|
||||
public static final int WORLDMAP_DISPLAY_TILESIZE = WORLDMAP_SCREENSHOT_TILESIZE;
|
||||
|
||||
public static void updateWorldMap(final WorldContext world, final Resources res) {
|
||||
updateWorldMap(world, world.model.currentMap, world.model.currentTileMap, world.tileManager.currentMapTiles, res);
|
||||
}
|
||||
|
||||
private static void updateWorldMap(
|
||||
final WorldContext world,
|
||||
final PredefinedMap map,
|
||||
final LayeredTileMap mapTiles,
|
||||
final TileCollection cachedTiles,
|
||||
final Resources res) {
|
||||
final String worldMapSegmentName = world.maps.getWorldMapSegmentNameForMap(map.name);
|
||||
if (worldMapSegmentName == null) return;
|
||||
|
||||
if (!shouldUpdateWorldMap(map, worldMapSegmentName, world.maps.worldMapRequiresUpdate)) return;
|
||||
|
||||
(new AsyncTask<Void, Void, Void>() {
|
||||
@Override
|
||||
protected Void doInBackground(Void... arg0) {
|
||||
final MapRenderer renderer = new MapRenderer(world, map, mapTiles, cachedTiles);
|
||||
try {
|
||||
updateCachedBitmap(map, renderer);
|
||||
updateWorldMapSegment(res, world, worldMapSegmentName);
|
||||
world.maps.worldMapRequiresUpdate = false;
|
||||
if (AndorsTrailApplication.DEVELOPMENT_DEBUGMESSAGES) {
|
||||
L.log("WorldMapController: Updated worldmap segment " + worldMapSegmentName + " for map " + map.name);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
L.log("Error creating worldmap file for map " + map.name + " : " + e.toString());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}).execute();
|
||||
}
|
||||
|
||||
private static boolean shouldUpdateWorldMap(PredefinedMap map, String worldMapSegmentName, boolean forceUpdate) {
|
||||
if (forceUpdate) return true;
|
||||
if (!map.visited) return true;
|
||||
File file = getFileForMap(map, false);
|
||||
if (!file.exists()) return true;
|
||||
|
||||
file = getCombinedWorldMapFile(worldMapSegmentName);
|
||||
if (!file.exists()) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void updateCachedBitmap(PredefinedMap map, MapRenderer renderer) throws IOException {
|
||||
ensureWorldmapDirectoryExists();
|
||||
|
||||
File file = getFileForMap(map, false);
|
||||
if (file.exists()) return;
|
||||
|
||||
Bitmap image = renderer.drawMap();
|
||||
FileOutputStream fos = new FileOutputStream(file);
|
||||
image.compress(Bitmap.CompressFormat.PNG, 70, fos);
|
||||
fos.flush();
|
||||
fos.close();
|
||||
image.recycle();
|
||||
L.log("WorldMapController: Wrote " + file.getAbsolutePath());
|
||||
}
|
||||
|
||||
private static final class MapRenderer {
|
||||
private final PredefinedMap map;
|
||||
private final LayeredTileMap mapTiles;
|
||||
private final TileCollection cachedTiles;
|
||||
private final int tileSize;
|
||||
private final float scale;
|
||||
private final Paint mPaint = new Paint();
|
||||
|
||||
public MapRenderer(final WorldContext world, final PredefinedMap map, final LayeredTileMap mapTiles, final TileCollection cachedTiles) {
|
||||
this.map = map;
|
||||
this.mapTiles = mapTiles;
|
||||
this.cachedTiles = cachedTiles;
|
||||
this.tileSize = world.tileManager.tileSize;
|
||||
this.scale = (float) WORLDMAP_SCREENSHOT_TILESIZE / world.tileManager.tileSize;
|
||||
mapTiles.setColorFilter(mPaint);
|
||||
}
|
||||
|
||||
public Bitmap drawMap() {
|
||||
Bitmap image = Bitmap.createBitmap(map.size.width * WORLDMAP_SCREENSHOT_TILESIZE, map.size.height * WORLDMAP_SCREENSHOT_TILESIZE, Config.RGB_565);
|
||||
image.setDensity(Bitmap.DENSITY_NONE);
|
||||
Canvas canvas = new Canvas(image);
|
||||
canvas.scale(scale, scale);
|
||||
|
||||
synchronized (cachedTiles) {
|
||||
drawMapLayer(canvas, mapTiles.currentLayout.layerGround);
|
||||
tryDrawMapLayer(canvas, mapTiles.currentLayout.layerObjects);
|
||||
tryDrawMapLayer(canvas, mapTiles.currentLayout.layerAbove);
|
||||
}
|
||||
return image;
|
||||
}
|
||||
|
||||
private void tryDrawMapLayer(Canvas canvas, final MapLayer layer) {
|
||||
if (layer != null) drawMapLayer(canvas, layer);
|
||||
}
|
||||
|
||||
private void drawMapLayer(Canvas canvas, final MapLayer layer) {
|
||||
int py = 0;
|
||||
for (int y = 0; y < map.size.height; ++y, py += tileSize) {
|
||||
int px = 0;
|
||||
for (int x = 0; x < map.size.width; ++x, px += tileSize) {
|
||||
final int tile = layer.tiles[x][y];
|
||||
if (tile == 0) continue;
|
||||
cachedTiles.drawTile(canvas, tile, px, py, mPaint);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void ensureWorldmapDirectoryExists() throws IOException {
|
||||
File root = Environment.getExternalStorageDirectory();
|
||||
File dir = new File(root, Constants.FILENAME_SAVEGAME_DIRECTORY);
|
||||
if (!dir.exists()) dir.mkdir();
|
||||
dir = new File(dir, Constants.FILENAME_WORLDMAP_DIRECTORY);
|
||||
if (!dir.exists()) dir.mkdir();
|
||||
|
||||
File noMediaFile = new File(dir, ".nomedia");
|
||||
if (!noMediaFile.exists()) noMediaFile.createNewFile();
|
||||
}
|
||||
public static boolean fileForMapExists(PredefinedMap map) {
|
||||
if (map.lastSeenLayoutHash.length() > 0) {
|
||||
return getPngFile(map.name + '.' + map.lastSeenLayoutHash).exists();
|
||||
}
|
||||
return getPngFile(map.name).exists();
|
||||
}
|
||||
private static File getFileForMap(PredefinedMap map, boolean verifyFileExists) {
|
||||
if (map.lastSeenLayoutHash.length() > 0) {
|
||||
File fileWithHash = getPngFile(map.name + '.' + map.lastSeenLayoutHash);
|
||||
if (!verifyFileExists) return fileWithHash;
|
||||
else if (fileWithHash.exists()) return fileWithHash;
|
||||
}
|
||||
return getPngFile(map.name);
|
||||
}
|
||||
private static File getPngFile(String fileName) {
|
||||
return new File(getWorldmapDirectory(), fileName + ".png");
|
||||
}
|
||||
private static File getWorldmapDirectory() {
|
||||
File dir = Environment.getExternalStorageDirectory();
|
||||
dir = new File(dir, Constants.FILENAME_SAVEGAME_DIRECTORY);
|
||||
return new File(dir, Constants.FILENAME_WORLDMAP_DIRECTORY);
|
||||
}
|
||||
public static File getCombinedWorldMapFile(String segmentName) {
|
||||
return new File(getWorldmapDirectory(), Constants.FILENAME_WORLDMAP_HTMLFILE_PREFIX + segmentName + Constants.FILENAME_WORLDMAP_HTMLFILE_SUFFIX);
|
||||
}
|
||||
|
||||
private static String getWorldMapSegmentAsHtml(Resources res, WorldContext world, String segmentName) {
|
||||
WorldMapSegment segment = world.maps.worldMapSegments.get(segmentName);
|
||||
|
||||
Map<String, File> displayedMapFilenamesPerMapName = new HashMap<String, File>(segment.maps.size());
|
||||
Coord offsetWorldmapTo = new Coord(999999, 999999);
|
||||
for (WorldMapSegmentMap map : segment.maps.values()) {
|
||||
PredefinedMap predefinedMap = world.maps.findPredefinedMap(map.mapName);
|
||||
if (predefinedMap == null) continue;
|
||||
if (!predefinedMap.visited) continue;
|
||||
File f = WorldMapController.getFileForMap(predefinedMap, true);
|
||||
if (!f.exists()) continue;
|
||||
displayedMapFilenamesPerMapName.put(map.mapName, f);
|
||||
|
||||
offsetWorldmapTo.x = Math.min(offsetWorldmapTo.x, map.worldPosition.x);
|
||||
offsetWorldmapTo.y = Math.min(offsetWorldmapTo.y, map.worldPosition.y);
|
||||
}
|
||||
|
||||
Coord bottomRight = new Coord(0, 0);
|
||||
|
||||
StringBuilder mapsAsHtml = new StringBuilder(1000);
|
||||
for (WorldMapSegmentMap segmentMap : segment.maps.values()) {
|
||||
File f = displayedMapFilenamesPerMapName.get(segmentMap.mapName);
|
||||
if (f == null) continue;
|
||||
|
||||
Size size = getMapSize(segmentMap, world);
|
||||
mapsAsHtml
|
||||
.append("<img src=\"")
|
||||
.append(f.getName())
|
||||
.append("\" id=\"")
|
||||
.append(segmentMap.mapName)
|
||||
.append("\" style=\"width:")
|
||||
.append(size.width * WorldMapController.WORLDMAP_DISPLAY_TILESIZE)
|
||||
.append("px; height:")
|
||||
.append(size.height * WorldMapController.WORLDMAP_DISPLAY_TILESIZE)
|
||||
.append("px; left:")
|
||||
.append((segmentMap.worldPosition.x - offsetWorldmapTo.x) * WorldMapController.WORLDMAP_DISPLAY_TILESIZE)
|
||||
.append("px; top:")
|
||||
.append((segmentMap.worldPosition.y - offsetWorldmapTo.y) * WorldMapController.WORLDMAP_DISPLAY_TILESIZE)
|
||||
.append("px;\" />");
|
||||
if (AndorsTrailApplication.DEVELOPMENT_DEBUGMESSAGES) mapsAsHtml.append('\n');
|
||||
|
||||
bottomRight.x = Math.max(bottomRight.x, segmentMap.worldPosition.x + size.width);
|
||||
bottomRight.y = Math.max(bottomRight.y, segmentMap.worldPosition.y + size.height);
|
||||
}
|
||||
Size worldmapSegmentSize = new Size(
|
||||
(bottomRight.x - offsetWorldmapTo.x) * WorldMapController.WORLDMAP_DISPLAY_TILESIZE
|
||||
,(bottomRight.y - offsetWorldmapTo.y) * WorldMapController.WORLDMAP_DISPLAY_TILESIZE
|
||||
);
|
||||
|
||||
StringBuilder namedAreasAsHtml = new StringBuilder(500);
|
||||
for (NamedWorldMapArea area : segment.namedAreas.values()) {
|
||||
CoordRect r = determineNamedAreaBoundary(area, segment, world, displayedMapFilenamesPerMapName.keySet());
|
||||
if (r == null) continue;
|
||||
namedAreasAsHtml
|
||||
.append("<div class=\"namedarea ")
|
||||
.append(area.type)
|
||||
.append("\" style=\"width:")
|
||||
.append(r.size.width * WorldMapController.WORLDMAP_DISPLAY_TILESIZE)
|
||||
.append("px; line-height:")
|
||||
.append(r.size.height * WorldMapController.WORLDMAP_DISPLAY_TILESIZE)
|
||||
.append("px; left:")
|
||||
.append((r.topLeft.x - offsetWorldmapTo.x) * WorldMapController.WORLDMAP_DISPLAY_TILESIZE)
|
||||
.append("px; top:")
|
||||
.append((r.topLeft.y - offsetWorldmapTo.y) * WorldMapController.WORLDMAP_DISPLAY_TILESIZE)
|
||||
.append("px;\"><span>")
|
||||
.append(area.name)
|
||||
.append("</span></div>");
|
||||
if (AndorsTrailApplication.DEVELOPMENT_DEBUGMESSAGES) namedAreasAsHtml.append('\n');
|
||||
}
|
||||
|
||||
return res.getString(R.string.worldmap_template)
|
||||
.replace("{{maps}}", mapsAsHtml.toString())
|
||||
.replace("{{areas}}", namedAreasAsHtml.toString())
|
||||
.replace("{{sizex}}", Integer.toString(worldmapSegmentSize.width))
|
||||
.replace("{{sizey}}", Integer.toString(worldmapSegmentSize.height))
|
||||
.replace("{{offsetx}}", Integer.toString(offsetWorldmapTo.x * WorldMapController.WORLDMAP_DISPLAY_TILESIZE))
|
||||
.replace("{{offsety}}", Integer.toString(offsetWorldmapTo.y * WorldMapController.WORLDMAP_DISPLAY_TILESIZE));
|
||||
}
|
||||
|
||||
private static Size getMapSize(WorldMapSegmentMap map, WorldContext world) {
|
||||
return world.maps.findPredefinedMap(map.mapName).size;
|
||||
}
|
||||
|
||||
private static CoordRect determineNamedAreaBoundary(NamedWorldMapArea area, WorldMapSegment segment, WorldContext world, Set<String> displayedMapNames) {
|
||||
Coord topLeft = null;
|
||||
Coord bottomRight = null;
|
||||
|
||||
for (String mapName : area.mapNames) {
|
||||
if (!displayedMapNames.contains(mapName)) continue;
|
||||
WorldMapSegmentMap map = segment.maps.get(mapName);
|
||||
Size size = getMapSize(map, world);
|
||||
if (topLeft == null) {
|
||||
topLeft = new Coord(map.worldPosition);
|
||||
} else {
|
||||
topLeft.x = Math.min(topLeft.x, map.worldPosition.x);
|
||||
topLeft.y = Math.min(topLeft.y, map.worldPosition.y);
|
||||
}
|
||||
if (bottomRight == null) {
|
||||
bottomRight = new Coord(map.worldPosition.x + size.width, map.worldPosition.y + size.height);
|
||||
} else {
|
||||
bottomRight.x = Math.max(bottomRight.x, map.worldPosition.x + size.width);
|
||||
bottomRight.y = Math.max(bottomRight.y, map.worldPosition.y + size.height);
|
||||
}
|
||||
}
|
||||
if (topLeft == null) return null;
|
||||
return new CoordRect(topLeft, new Size(bottomRight.x - topLeft.x, bottomRight.y - topLeft.y));
|
||||
}
|
||||
|
||||
private static void updateWorldMapSegment(Resources res, WorldContext world, String segmentName) throws IOException {
|
||||
String mapAsHtml = getWorldMapSegmentAsHtml(res, world, segmentName);
|
||||
File outputFile = getCombinedWorldMapFile(segmentName);
|
||||
PrintWriter pw = new PrintWriter(outputFile);
|
||||
pw.write(mapAsHtml);
|
||||
pw.close();
|
||||
}
|
||||
|
||||
public static boolean displayWorldMap(Context context, WorldContext world) {
|
||||
String worldMapSegmentName = world.maps.getWorldMapSegmentNameForMap(world.model.currentMap.name);
|
||||
if (worldMapSegmentName == null) {
|
||||
Toast.makeText(context, context.getResources().getString(R.string.display_worldmap_not_available), Toast.LENGTH_LONG).show();
|
||||
return false;
|
||||
}
|
||||
|
||||
Intent intent = new Intent(context, DisplayWorldMapActivity.class);
|
||||
intent.putExtra("worldMapSegmentName", worldMapSegmentName);
|
||||
context.startActivity(intent);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
package com.gpl.rpg.AndorsTrail.controller;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Bitmap.Config;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Environment;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
|
||||
import com.gpl.rpg.AndorsTrail.R;
|
||||
import com.gpl.rpg.AndorsTrail.activity.DisplayWorldMapActivity;
|
||||
import com.gpl.rpg.AndorsTrail.context.WorldContext;
|
||||
import com.gpl.rpg.AndorsTrail.model.map.LayeredTileMap;
|
||||
import com.gpl.rpg.AndorsTrail.model.map.MapLayer;
|
||||
import com.gpl.rpg.AndorsTrail.model.map.PredefinedMap;
|
||||
import com.gpl.rpg.AndorsTrail.model.map.WorldMapSegment;
|
||||
import com.gpl.rpg.AndorsTrail.model.map.WorldMapSegment.NamedWorldMapArea;
|
||||
import com.gpl.rpg.AndorsTrail.model.map.WorldMapSegment.WorldMapSegmentMap;
|
||||
import com.gpl.rpg.AndorsTrail.resource.tiles.TileCollection;
|
||||
import com.gpl.rpg.AndorsTrail.util.Coord;
|
||||
import com.gpl.rpg.AndorsTrail.util.CoordRect;
|
||||
import com.gpl.rpg.AndorsTrail.util.L;
|
||||
import com.gpl.rpg.AndorsTrail.util.Size;
|
||||
|
||||
public final class WorldMapController {
|
||||
|
||||
private static final int WORLDMAP_SCREENSHOT_TILESIZE = 8;
|
||||
public static final int WORLDMAP_DISPLAY_TILESIZE = WORLDMAP_SCREENSHOT_TILESIZE;
|
||||
|
||||
public static void updateWorldMap(final WorldContext world, final Resources res) {
|
||||
updateWorldMap(world, world.model.currentMap, world.model.currentTileMap, world.tileManager.currentMapTiles, res);
|
||||
}
|
||||
|
||||
private static void updateWorldMap(
|
||||
final WorldContext world,
|
||||
final PredefinedMap map,
|
||||
final LayeredTileMap mapTiles,
|
||||
final TileCollection cachedTiles,
|
||||
final Resources res) {
|
||||
final String worldMapSegmentName = world.maps.getWorldMapSegmentNameForMap(map.name);
|
||||
if (worldMapSegmentName == null) return;
|
||||
|
||||
if (!shouldUpdateWorldMap(map, worldMapSegmentName, world.maps.worldMapRequiresUpdate)) return;
|
||||
|
||||
(new AsyncTask<Void, Void, Void>() {
|
||||
@Override
|
||||
protected Void doInBackground(Void... arg0) {
|
||||
final MapRenderer renderer = new MapRenderer(world, map, mapTiles, cachedTiles);
|
||||
try {
|
||||
updateCachedBitmap(map, renderer);
|
||||
updateWorldMapSegment(res, world, worldMapSegmentName);
|
||||
world.maps.worldMapRequiresUpdate = false;
|
||||
if (AndorsTrailApplication.DEVELOPMENT_DEBUGMESSAGES) {
|
||||
L.log("WorldMapController: Updated worldmap segment " + worldMapSegmentName + " for map " + map.name);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
L.log("Error creating worldmap file for map " + map.name + " : " + e.toString());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}).execute();
|
||||
}
|
||||
|
||||
private static boolean shouldUpdateWorldMap(PredefinedMap map, String worldMapSegmentName, boolean forceUpdate) {
|
||||
if (forceUpdate) return true;
|
||||
if (!map.visited) return true;
|
||||
File file = getFileForMap(map, false);
|
||||
if (!file.exists()) return true;
|
||||
|
||||
file = getCombinedWorldMapFile(worldMapSegmentName);
|
||||
if (!file.exists()) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void updateCachedBitmap(PredefinedMap map, MapRenderer renderer) throws IOException {
|
||||
ensureWorldmapDirectoryExists();
|
||||
|
||||
File file = getFileForMap(map, false);
|
||||
if (file.exists()) return;
|
||||
|
||||
Bitmap image = renderer.drawMap();
|
||||
FileOutputStream fos = new FileOutputStream(file);
|
||||
image.compress(Bitmap.CompressFormat.PNG, 70, fos);
|
||||
fos.flush();
|
||||
fos.close();
|
||||
image.recycle();
|
||||
L.log("WorldMapController: Wrote " + file.getAbsolutePath());
|
||||
}
|
||||
|
||||
private static final class MapRenderer {
|
||||
private final PredefinedMap map;
|
||||
private final LayeredTileMap mapTiles;
|
||||
private final TileCollection cachedTiles;
|
||||
private final int tileSize;
|
||||
private final float scale;
|
||||
private final Paint mPaint = new Paint();
|
||||
|
||||
public MapRenderer(final WorldContext world, final PredefinedMap map, final LayeredTileMap mapTiles, final TileCollection cachedTiles) {
|
||||
this.map = map;
|
||||
this.mapTiles = mapTiles;
|
||||
this.cachedTiles = cachedTiles;
|
||||
this.tileSize = world.tileManager.tileSize;
|
||||
this.scale = (float) WORLDMAP_SCREENSHOT_TILESIZE / world.tileManager.tileSize;
|
||||
mapTiles.setColorFilter(mPaint);
|
||||
}
|
||||
|
||||
public Bitmap drawMap() {
|
||||
Bitmap image = Bitmap.createBitmap(map.size.width * WORLDMAP_SCREENSHOT_TILESIZE, map.size.height * WORLDMAP_SCREENSHOT_TILESIZE, Config.RGB_565);
|
||||
image.setDensity(Bitmap.DENSITY_NONE);
|
||||
Canvas canvas = new Canvas(image);
|
||||
canvas.scale(scale, scale);
|
||||
|
||||
synchronized (cachedTiles) {
|
||||
drawMapLayer(canvas, mapTiles.currentLayout.layerGround);
|
||||
tryDrawMapLayer(canvas, mapTiles.currentLayout.layerObjects);
|
||||
tryDrawMapLayer(canvas, mapTiles.currentLayout.layerAbove);
|
||||
tryDrawMapLayer(canvas, mapTiles.currentLayout.layerTop);
|
||||
}
|
||||
return image;
|
||||
}
|
||||
|
||||
private void tryDrawMapLayer(Canvas canvas, final MapLayer layer) {
|
||||
if (layer != null) drawMapLayer(canvas, layer);
|
||||
}
|
||||
|
||||
private void drawMapLayer(Canvas canvas, final MapLayer layer) {
|
||||
int py = 0;
|
||||
for (int y = 0; y < map.size.height; ++y, py += tileSize) {
|
||||
int px = 0;
|
||||
for (int x = 0; x < map.size.width; ++x, px += tileSize) {
|
||||
final int tile = layer.tiles[x][y];
|
||||
if (tile == 0) continue;
|
||||
cachedTiles.drawTile(canvas, tile, px, py, mPaint);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void ensureWorldmapDirectoryExists() throws IOException {
|
||||
File root = Environment.getExternalStorageDirectory();
|
||||
File dir = new File(root, Constants.FILENAME_SAVEGAME_DIRECTORY);
|
||||
if (!dir.exists()) dir.mkdir();
|
||||
dir = new File(dir, Constants.FILENAME_WORLDMAP_DIRECTORY);
|
||||
if (!dir.exists()) dir.mkdir();
|
||||
|
||||
File noMediaFile = new File(dir, ".nomedia");
|
||||
if (!noMediaFile.exists()) noMediaFile.createNewFile();
|
||||
}
|
||||
public static boolean fileForMapExists(PredefinedMap map) {
|
||||
if (map.lastSeenLayoutHash.length() > 0) {
|
||||
return getPngFile(map.name + '.' + map.lastSeenLayoutHash).exists();
|
||||
}
|
||||
return getPngFile(map.name).exists();
|
||||
}
|
||||
private static File getFileForMap(PredefinedMap map, boolean verifyFileExists) {
|
||||
if (map.lastSeenLayoutHash.length() > 0) {
|
||||
File fileWithHash = getPngFile(map.name + '.' + map.lastSeenLayoutHash);
|
||||
if (!verifyFileExists) return fileWithHash;
|
||||
else if (fileWithHash.exists()) return fileWithHash;
|
||||
}
|
||||
return getPngFile(map.name);
|
||||
}
|
||||
private static File getPngFile(String fileName) {
|
||||
return new File(getWorldmapDirectory(), fileName + ".png");
|
||||
}
|
||||
private static File getWorldmapDirectory() {
|
||||
File dir = Environment.getExternalStorageDirectory();
|
||||
dir = new File(dir, Constants.FILENAME_SAVEGAME_DIRECTORY);
|
||||
return new File(dir, Constants.FILENAME_WORLDMAP_DIRECTORY);
|
||||
}
|
||||
public static File getCombinedWorldMapFile(String segmentName) {
|
||||
return new File(getWorldmapDirectory(), Constants.FILENAME_WORLDMAP_HTMLFILE_PREFIX + segmentName + Constants.FILENAME_WORLDMAP_HTMLFILE_SUFFIX);
|
||||
}
|
||||
|
||||
private static String getWorldMapSegmentAsHtml(Resources res, WorldContext world, String segmentName) {
|
||||
WorldMapSegment segment = world.maps.worldMapSegments.get(segmentName);
|
||||
|
||||
Map<String, File> displayedMapFilenamesPerMapName = new HashMap<String, File>(segment.maps.size());
|
||||
Coord offsetWorldmapTo = new Coord(999999, 999999);
|
||||
for (WorldMapSegmentMap map : segment.maps.values()) {
|
||||
PredefinedMap predefinedMap = world.maps.findPredefinedMap(map.mapName);
|
||||
if (predefinedMap == null) continue;
|
||||
if (!predefinedMap.visited) continue;
|
||||
File f = WorldMapController.getFileForMap(predefinedMap, true);
|
||||
if (!f.exists()) continue;
|
||||
displayedMapFilenamesPerMapName.put(map.mapName, f);
|
||||
|
||||
offsetWorldmapTo.x = Math.min(offsetWorldmapTo.x, map.worldPosition.x);
|
||||
offsetWorldmapTo.y = Math.min(offsetWorldmapTo.y, map.worldPosition.y);
|
||||
}
|
||||
|
||||
Coord bottomRight = new Coord(0, 0);
|
||||
|
||||
StringBuilder mapsAsHtml = new StringBuilder(1000);
|
||||
for (WorldMapSegmentMap segmentMap : segment.maps.values()) {
|
||||
File f = displayedMapFilenamesPerMapName.get(segmentMap.mapName);
|
||||
if (f == null) continue;
|
||||
|
||||
Size size = getMapSize(segmentMap, world);
|
||||
mapsAsHtml
|
||||
.append("<img src=\"")
|
||||
.append(f.getName())
|
||||
.append("\" id=\"")
|
||||
.append(segmentMap.mapName)
|
||||
.append("\" style=\"width:")
|
||||
.append(size.width * WorldMapController.WORLDMAP_DISPLAY_TILESIZE)
|
||||
.append("px; height:")
|
||||
.append(size.height * WorldMapController.WORLDMAP_DISPLAY_TILESIZE)
|
||||
.append("px; left:")
|
||||
.append((segmentMap.worldPosition.x - offsetWorldmapTo.x) * WorldMapController.WORLDMAP_DISPLAY_TILESIZE)
|
||||
.append("px; top:")
|
||||
.append((segmentMap.worldPosition.y - offsetWorldmapTo.y) * WorldMapController.WORLDMAP_DISPLAY_TILESIZE)
|
||||
.append("px;\" />");
|
||||
if (AndorsTrailApplication.DEVELOPMENT_DEBUGMESSAGES) mapsAsHtml.append('\n');
|
||||
|
||||
bottomRight.x = Math.max(bottomRight.x, segmentMap.worldPosition.x + size.width);
|
||||
bottomRight.y = Math.max(bottomRight.y, segmentMap.worldPosition.y + size.height);
|
||||
}
|
||||
Size worldmapSegmentSize = new Size(
|
||||
(bottomRight.x - offsetWorldmapTo.x) * WorldMapController.WORLDMAP_DISPLAY_TILESIZE
|
||||
,(bottomRight.y - offsetWorldmapTo.y) * WorldMapController.WORLDMAP_DISPLAY_TILESIZE
|
||||
);
|
||||
|
||||
StringBuilder namedAreasAsHtml = new StringBuilder(500);
|
||||
for (NamedWorldMapArea area : segment.namedAreas.values()) {
|
||||
CoordRect r = determineNamedAreaBoundary(area, segment, world, displayedMapFilenamesPerMapName.keySet());
|
||||
if (r == null) continue;
|
||||
namedAreasAsHtml
|
||||
.append("<div class=\"namedarea ")
|
||||
.append(area.type)
|
||||
.append("\" style=\"width:")
|
||||
.append(r.size.width * WorldMapController.WORLDMAP_DISPLAY_TILESIZE)
|
||||
.append("px; line-height:")
|
||||
.append(r.size.height * WorldMapController.WORLDMAP_DISPLAY_TILESIZE)
|
||||
.append("px; left:")
|
||||
.append((r.topLeft.x - offsetWorldmapTo.x) * WorldMapController.WORLDMAP_DISPLAY_TILESIZE)
|
||||
.append("px; top:")
|
||||
.append((r.topLeft.y - offsetWorldmapTo.y) * WorldMapController.WORLDMAP_DISPLAY_TILESIZE)
|
||||
.append("px;\"><span>")
|
||||
.append(area.name)
|
||||
.append("</span></div>");
|
||||
if (AndorsTrailApplication.DEVELOPMENT_DEBUGMESSAGES) namedAreasAsHtml.append('\n');
|
||||
}
|
||||
|
||||
return res.getString(R.string.worldmap_template)
|
||||
.replace("{{maps}}", mapsAsHtml.toString())
|
||||
.replace("{{areas}}", namedAreasAsHtml.toString())
|
||||
.replace("{{sizex}}", Integer.toString(worldmapSegmentSize.width))
|
||||
.replace("{{sizey}}", Integer.toString(worldmapSegmentSize.height))
|
||||
.replace("{{offsetx}}", Integer.toString(offsetWorldmapTo.x * WorldMapController.WORLDMAP_DISPLAY_TILESIZE))
|
||||
.replace("{{offsety}}", Integer.toString(offsetWorldmapTo.y * WorldMapController.WORLDMAP_DISPLAY_TILESIZE));
|
||||
}
|
||||
|
||||
private static Size getMapSize(WorldMapSegmentMap map, WorldContext world) {
|
||||
return world.maps.findPredefinedMap(map.mapName).size;
|
||||
}
|
||||
|
||||
private static CoordRect determineNamedAreaBoundary(NamedWorldMapArea area, WorldMapSegment segment, WorldContext world, Set<String> displayedMapNames) {
|
||||
Coord topLeft = null;
|
||||
Coord bottomRight = null;
|
||||
|
||||
for (String mapName : area.mapNames) {
|
||||
if (!displayedMapNames.contains(mapName)) continue;
|
||||
WorldMapSegmentMap map = segment.maps.get(mapName);
|
||||
Size size = getMapSize(map, world);
|
||||
if (topLeft == null) {
|
||||
topLeft = new Coord(map.worldPosition);
|
||||
} else {
|
||||
topLeft.x = Math.min(topLeft.x, map.worldPosition.x);
|
||||
topLeft.y = Math.min(topLeft.y, map.worldPosition.y);
|
||||
}
|
||||
if (bottomRight == null) {
|
||||
bottomRight = new Coord(map.worldPosition.x + size.width, map.worldPosition.y + size.height);
|
||||
} else {
|
||||
bottomRight.x = Math.max(bottomRight.x, map.worldPosition.x + size.width);
|
||||
bottomRight.y = Math.max(bottomRight.y, map.worldPosition.y + size.height);
|
||||
}
|
||||
}
|
||||
if (topLeft == null) return null;
|
||||
return new CoordRect(topLeft, new Size(bottomRight.x - topLeft.x, bottomRight.y - topLeft.y));
|
||||
}
|
||||
|
||||
private static void updateWorldMapSegment(Resources res, WorldContext world, String segmentName) throws IOException {
|
||||
String mapAsHtml = getWorldMapSegmentAsHtml(res, world, segmentName);
|
||||
File outputFile = getCombinedWorldMapFile(segmentName);
|
||||
PrintWriter pw = new PrintWriter(outputFile);
|
||||
pw.write(mapAsHtml);
|
||||
pw.close();
|
||||
}
|
||||
|
||||
public static boolean displayWorldMap(Context context, WorldContext world) {
|
||||
String worldMapSegmentName = world.maps.getWorldMapSegmentNameForMap(world.model.currentMap.name);
|
||||
if (worldMapSegmentName == null) {
|
||||
Toast.makeText(context, context.getResources().getString(R.string.display_worldmap_not_available), Toast.LENGTH_LONG).show();
|
||||
return false;
|
||||
}
|
||||
|
||||
Intent intent = new Intent(context, DisplayWorldMapActivity.class);
|
||||
intent.putExtra("worldMapSegmentName", worldMapSegmentName);
|
||||
context.startActivity(intent);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,397 +1,391 @@
|
||||
package com.gpl.rpg.AndorsTrail.model.map;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
|
||||
import com.gpl.rpg.AndorsTrail.context.ControllerContext;
|
||||
import com.gpl.rpg.AndorsTrail.context.WorldContext;
|
||||
import com.gpl.rpg.AndorsTrail.controller.Constants;
|
||||
import com.gpl.rpg.AndorsTrail.controller.VisualEffectController.BloodSplatter;
|
||||
import com.gpl.rpg.AndorsTrail.model.actor.Monster;
|
||||
import com.gpl.rpg.AndorsTrail.model.item.ItemType;
|
||||
import com.gpl.rpg.AndorsTrail.model.item.Loot;
|
||||
import com.gpl.rpg.AndorsTrail.model.map.MapObject.MapObjectType;
|
||||
import com.gpl.rpg.AndorsTrail.util.Coord;
|
||||
import com.gpl.rpg.AndorsTrail.util.CoordRect;
|
||||
import com.gpl.rpg.AndorsTrail.util.L;
|
||||
import com.gpl.rpg.AndorsTrail.util.Size;
|
||||
|
||||
public final class PredefinedMap {
|
||||
private static final long VISIT_RESET = 0;
|
||||
|
||||
public final int xmlResourceId;
|
||||
public final String name;
|
||||
public final Size size;
|
||||
public final MapObject[] eventObjects;
|
||||
public final MonsterSpawnArea[] spawnAreas;
|
||||
public final List<String> initiallyActiveMapObjectGroups;
|
||||
public final List<String> activeMapObjectGroups;
|
||||
public final ArrayList<Loot> groundBags = new ArrayList<Loot>();
|
||||
public boolean visited = false;
|
||||
public long lastVisitTime = VISIT_RESET;
|
||||
public String lastSeenLayoutHash = "";
|
||||
public final boolean isOutdoors;
|
||||
public String currentColorFilter = null;
|
||||
|
||||
public final ArrayList<BloodSplatter> splatters = new ArrayList<BloodSplatter>();
|
||||
|
||||
public PredefinedMap(
|
||||
int xmlResourceId
|
||||
, String name
|
||||
, Size size
|
||||
, MapObject[] eventObjects
|
||||
, MonsterSpawnArea[] spawnAreas
|
||||
, List<String> initiallyActiveMapObjectGroups
|
||||
, boolean isOutdoors
|
||||
) {
|
||||
this.xmlResourceId = xmlResourceId;
|
||||
this.name = name;
|
||||
this.size = size;
|
||||
this.eventObjects = eventObjects;
|
||||
this.spawnAreas = spawnAreas;
|
||||
this.initiallyActiveMapObjectGroups = initiallyActiveMapObjectGroups;
|
||||
this.activeMapObjectGroups = new LinkedList<String>();
|
||||
this.activeMapObjectGroups.addAll(this.initiallyActiveMapObjectGroups);
|
||||
activateMapObjects();
|
||||
assert(size.width > 0);
|
||||
assert(size.height > 0);
|
||||
this.isOutdoors = isOutdoors;
|
||||
}
|
||||
|
||||
public final boolean isOutside(final Coord p) { return isOutside(p.x, p.y); }
|
||||
public final boolean isOutside(final int x, final int y) {
|
||||
if (x < 0) return true;
|
||||
if (y < 0) return true;
|
||||
if (x >= size.width) return true;
|
||||
if (y >= size.height) return true;
|
||||
return false;
|
||||
}
|
||||
public final boolean isOutside(final CoordRect area) {
|
||||
if (isOutside(area.topLeft)) return true;
|
||||
if (area.topLeft.x + area.size.width > size.width) return true;
|
||||
if (area.topLeft.y + area.size.height > size.height) return true;
|
||||
return false;
|
||||
}
|
||||
public boolean intersects(CoordRect area) {
|
||||
return new CoordRect(new Coord(0,0), size).intersects(area);
|
||||
}
|
||||
|
||||
public MapObject findEventObject(MapObject.MapObjectType objectType, String name) {
|
||||
for (MapObject o : eventObjects) {
|
||||
if (o.type != objectType) continue;
|
||||
if (!name.equals(o.id)) continue;
|
||||
return o;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public List<MapObject> getActiveEventObjectsAt(final Coord p) {
|
||||
List<MapObject> result = null;
|
||||
for (MapObject o : eventObjects) {
|
||||
if (!o.isActive) continue;
|
||||
if (!o.position.contains(p)) continue;
|
||||
//if (!activeMapObjectGroups.contains(o.group)) continue;
|
||||
if (result == null) result = new ArrayList<MapObject>();
|
||||
result.add(o);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
public boolean hasContainerAt(final Coord p) {
|
||||
for (MapObject o : eventObjects) {
|
||||
if (!o.isActive) continue;
|
||||
if (o.type != MapObject.MapObjectType.container) continue;
|
||||
if (!o.position.contains(p)) continue;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public Monster getMonsterAt(final CoordRect p) {
|
||||
return getMonsterAt(p, null);
|
||||
}
|
||||
public Monster getMonsterAt(final CoordRect p, Monster exceptMe) {
|
||||
for (MonsterSpawnArea a : spawnAreas) {
|
||||
Monster m = a.getMonsterAt(p);
|
||||
if (m != null && (exceptMe == null || exceptMe != m)) return m;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public Monster getMonsterAt(final Coord p) { return getMonsterAt(p.x, p.y); }
|
||||
public Monster getMonsterAt(final int x, final int y) {
|
||||
for (MonsterSpawnArea a : spawnAreas) {
|
||||
Monster m = a.getMonsterAt(x, y);
|
||||
if (m != null) return m;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Monster findSpawnedMonster(final String monsterTypeID) {
|
||||
for (MonsterSpawnArea a : spawnAreas) {
|
||||
Monster m = a.findSpawnedMonster(monsterTypeID);
|
||||
if (m != null) return m;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Loot getBagAt(final Coord p) {
|
||||
for (Loot l : groundBags) {
|
||||
if (l.position.equals(p)) return l;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public Loot getBagOrCreateAt(final Coord position) {
|
||||
Loot b = getBagAt(position);
|
||||
if (b != null) return b;
|
||||
boolean isContainer = hasContainerAt(position);
|
||||
b = new Loot(!isContainer);
|
||||
b.position.set(position);
|
||||
if (isOutside(position)) {
|
||||
if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
|
||||
L.log("WARNING: trying to place bag outside map. Map is " + size.toString() + ", bag tried to place at " + position.toString());
|
||||
}
|
||||
return b;
|
||||
}
|
||||
groundBags.add(b);
|
||||
return b;
|
||||
}
|
||||
public void itemDropped(ItemType itemType, int quantity, Coord position) {
|
||||
Loot l = getBagOrCreateAt(position);
|
||||
l.items.addItem(itemType, quantity);
|
||||
}
|
||||
public void removeGroundLoot(Loot loot) {
|
||||
groundBags.remove(loot);
|
||||
}
|
||||
public void resetForNewGame() {
|
||||
for (MonsterSpawnArea a : spawnAreas) {
|
||||
a.resetForNewGame();
|
||||
}
|
||||
activeMapObjectGroups.clear();
|
||||
activeMapObjectGroups.addAll(initiallyActiveMapObjectGroups);
|
||||
activateMapObjects();
|
||||
resetTemporaryData();
|
||||
groundBags.clear();
|
||||
visited = false;
|
||||
currentColorFilter = null;
|
||||
lastSeenLayoutHash = "";
|
||||
}
|
||||
|
||||
public boolean isRecentlyVisited() {
|
||||
if (lastVisitTime == VISIT_RESET) return false;
|
||||
return (System.currentTimeMillis() - lastVisitTime) < Constants.MAP_UNVISITED_RESPAWN_DURATION_MS;
|
||||
}
|
||||
public void updateLastVisitTime() {
|
||||
lastVisitTime = System.currentTimeMillis();
|
||||
}
|
||||
public void resetTemporaryData() {
|
||||
for(MonsterSpawnArea a : spawnAreas) {
|
||||
if (a.isUnique) a.resetShops();
|
||||
else a.removeAllMonsters();
|
||||
}
|
||||
splatters.clear();
|
||||
lastVisitTime = VISIT_RESET;
|
||||
}
|
||||
public boolean hasResetTemporaryData() {
|
||||
return lastVisitTime == VISIT_RESET;
|
||||
}
|
||||
|
||||
public void createAllContainerLoot() {
|
||||
for (MapObject o : eventObjects) {
|
||||
if (!o.isActive) continue;
|
||||
if (o.type != MapObject.MapObjectType.container) continue;
|
||||
createContainerLoot(o);
|
||||
}
|
||||
}
|
||||
|
||||
public void createContainerLoot(MapObject container) {
|
||||
Loot bag = getBagOrCreateAt(container.position.topLeft);
|
||||
container.dropList.createRandomLoot(bag, null);
|
||||
}
|
||||
|
||||
|
||||
private void activateMapObjects() {
|
||||
if (AndorsTrailApplication.DEVELOPMENT_DEBUGMESSAGES) {
|
||||
L.log("Applying active status to all map objects in map "+name);
|
||||
}
|
||||
for (MapObject o : eventObjects) {
|
||||
o.isActive = activeMapObjectGroups.contains(o.group);
|
||||
}
|
||||
}
|
||||
|
||||
public void activateMapObjectGroup(String group) {
|
||||
if (AndorsTrailApplication.DEVELOPMENT_DEBUGMESSAGES) {
|
||||
L.log("Applying active status to object group "+group+" in map "+name);
|
||||
}
|
||||
if (!activeMapObjectGroups.contains(group)) {
|
||||
activeMapObjectGroups.add(group);
|
||||
for (MapObject o : eventObjects) {
|
||||
if (o.group.equals(group)) {
|
||||
o.isActive = true;
|
||||
if (o.type == MapObjectType.container) createContainerLoot(o);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void deactivateMapObjectGroup(String group) {
|
||||
if (AndorsTrailApplication.DEVELOPMENT_DEBUGMESSAGES) {
|
||||
L.log("Removing active status to object group "+group+" in map"+name);
|
||||
}
|
||||
if (activeMapObjectGroups.contains(group)) {
|
||||
activeMapObjectGroups.remove(group);
|
||||
for (MapObject o : eventObjects) {
|
||||
if (o.group.equals(group)) {
|
||||
o.isActive = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ====== PARCELABLE ===================================================================
|
||||
|
||||
public void readFromParcel(DataInputStream src, WorldContext world, ControllerContext controllers, int fileversion) throws IOException {
|
||||
boolean shouldLoadMapData = true;
|
||||
if (fileversion >= 37) shouldLoadMapData = src.readBoolean();
|
||||
|
||||
int loadedSpawnAreas = 0;
|
||||
if (shouldLoadMapData) {
|
||||
loadedSpawnAreas = src.readInt();
|
||||
for(int i = 0; i < loadedSpawnAreas; ++i) {
|
||||
if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
|
||||
if (i >= this.spawnAreas.length) {
|
||||
L.log("WARNING: Trying to load monsters from savegame in map " + this.name + " for spawn #" + i + ". This will totally fail.");
|
||||
}
|
||||
}
|
||||
if(fileversion >= 43) {
|
||||
//Spawn areas now have unique IDs. Need to check as maps can change.
|
||||
String id = src.readUTF();
|
||||
int j = i;
|
||||
boolean found = false;
|
||||
do {
|
||||
if (this.spawnAreas[j].areaID.equals(id)) {
|
||||
this.spawnAreas[j].readFromParcel(src, world, fileversion);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
j = (j+1)%spawnAreas.length;
|
||||
} while (j != i);
|
||||
if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
|
||||
if (!found) {
|
||||
L.log("WARNING: Trying to load monsters from savegame in map " + this.name + " for spawn #" + id + " but this area cannot be found. This will totally fail.");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.spawnAreas[i].readFromParcel(src, world, fileversion);
|
||||
}
|
||||
}
|
||||
|
||||
activeMapObjectGroups.clear();
|
||||
if(fileversion >= 43) {
|
||||
int activeListLength = src.readInt();
|
||||
for (int i = 0; i < activeListLength; i++) {
|
||||
String activeGroupID = src.readUTF();
|
||||
activeMapObjectGroups.add(activeGroupID);
|
||||
}
|
||||
} else {
|
||||
activeMapObjectGroups.addAll(initiallyActiveMapObjectGroups);
|
||||
}
|
||||
activateMapObjects();
|
||||
|
||||
groundBags.clear();
|
||||
if (fileversion <= 5) return;
|
||||
|
||||
final int size2 = src.readInt();
|
||||
for(int i = 0; i < size2; ++i) {
|
||||
groundBags.add(new Loot(src, world, fileversion));
|
||||
}
|
||||
|
||||
if (fileversion <= 11) return;
|
||||
|
||||
if (fileversion < 37) visited = src.readBoolean();
|
||||
|
||||
if (fileversion <= 15) {
|
||||
if (visited) {
|
||||
lastVisitTime = System.currentTimeMillis();
|
||||
createAllContainerLoot();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (fileversion >= 43) {
|
||||
if (src.readBoolean()) {
|
||||
currentColorFilter = src.readUTF();
|
||||
} else {
|
||||
currentColorFilter = null;
|
||||
}
|
||||
}
|
||||
|
||||
lastVisitTime = src.readLong();
|
||||
|
||||
if (visited) {
|
||||
if (fileversion > 30 && fileversion < 36) {
|
||||
/*int lastVisitVersion = */src.readInt();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
activeMapObjectGroups.clear();
|
||||
activeMapObjectGroups.addAll(initiallyActiveMapObjectGroups);
|
||||
activateMapObjects();
|
||||
}
|
||||
if (fileversion >= 37) {
|
||||
if (fileversion < 41) visited = true;
|
||||
else visited = src.readBoolean();
|
||||
}
|
||||
|
||||
if (fileversion < 36) lastSeenLayoutHash = "";
|
||||
else lastSeenLayoutHash = src.readUTF();
|
||||
|
||||
for(int i = loadedSpawnAreas; i < spawnAreas.length; ++i) {
|
||||
MonsterSpawnArea area = this.spawnAreas[i];
|
||||
if (area.isUnique && visited) controllers.monsterSpawnController.spawnAllInArea(this, null, area, true);
|
||||
else area.resetForNewGame();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean shouldSaveMapData(WorldContext world) {
|
||||
if (!hasResetTemporaryData()) return true;
|
||||
if (this == world.model.currentMap) return true;
|
||||
if (!groundBags.isEmpty()) return true;
|
||||
for (MonsterSpawnArea a : spawnAreas) {
|
||||
if (this.visited && a.isUnique) return true;
|
||||
if (a.isSpawning != a.isSpawningForNewGame) return true;
|
||||
}
|
||||
if (!activeMapObjectGroups.containsAll(initiallyActiveMapObjectGroups)
|
||||
|| !initiallyActiveMapObjectGroups.containsAll(activeMapObjectGroups)) return true;
|
||||
if (currentColorFilter != null) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public void writeToParcel(DataOutputStream dest, WorldContext world) throws IOException {
|
||||
if (shouldSaveMapData(world)) {
|
||||
dest.writeBoolean(true);
|
||||
dest.writeInt(spawnAreas.length);
|
||||
for(MonsterSpawnArea a : spawnAreas) {
|
||||
dest.writeUTF(a.areaID);
|
||||
a.writeToParcel(dest);
|
||||
}
|
||||
dest.writeInt(activeMapObjectGroups.size());
|
||||
for(String s : activeMapObjectGroups) {
|
||||
dest.writeUTF(s);
|
||||
}
|
||||
dest.writeInt(groundBags.size());
|
||||
for(Loot l : groundBags) {
|
||||
l.writeToParcel(dest);
|
||||
}
|
||||
dest.writeBoolean(currentColorFilter != null);
|
||||
if (currentColorFilter != null) dest.writeUTF(currentColorFilter);
|
||||
dest.writeLong(lastVisitTime);
|
||||
} else {
|
||||
dest.writeBoolean(false);
|
||||
}
|
||||
dest.writeBoolean(visited);
|
||||
dest.writeUTF(lastSeenLayoutHash);
|
||||
}
|
||||
}
|
||||
package com.gpl.rpg.AndorsTrail.model.map;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
|
||||
import com.gpl.rpg.AndorsTrail.context.ControllerContext;
|
||||
import com.gpl.rpg.AndorsTrail.context.WorldContext;
|
||||
import com.gpl.rpg.AndorsTrail.controller.Constants;
|
||||
import com.gpl.rpg.AndorsTrail.controller.VisualEffectController.BloodSplatter;
|
||||
import com.gpl.rpg.AndorsTrail.model.actor.Monster;
|
||||
import com.gpl.rpg.AndorsTrail.model.item.ItemType;
|
||||
import com.gpl.rpg.AndorsTrail.model.item.Loot;
|
||||
import com.gpl.rpg.AndorsTrail.model.map.MapObject.MapObjectType;
|
||||
import com.gpl.rpg.AndorsTrail.util.Coord;
|
||||
import com.gpl.rpg.AndorsTrail.util.CoordRect;
|
||||
import com.gpl.rpg.AndorsTrail.util.L;
|
||||
import com.gpl.rpg.AndorsTrail.util.Size;
|
||||
|
||||
public final class PredefinedMap {
|
||||
private static final long VISIT_RESET = 0;
|
||||
|
||||
public final int xmlResourceId;
|
||||
public final String name;
|
||||
public final Size size;
|
||||
public final MapObject[] eventObjects;
|
||||
public final MonsterSpawnArea[] spawnAreas;
|
||||
public final List<String> initiallyActiveMapObjectGroups;
|
||||
public final List<String> activeMapObjectGroups;
|
||||
public final ArrayList<Loot> groundBags = new ArrayList<Loot>();
|
||||
public final String initialColorFilter;
|
||||
public boolean visited = false;
|
||||
public long lastVisitTime = VISIT_RESET;
|
||||
public String lastSeenLayoutHash = "";
|
||||
public final boolean isOutdoors;
|
||||
public String currentColorFilter = null;
|
||||
|
||||
public final ArrayList<BloodSplatter> splatters = new ArrayList<BloodSplatter>();
|
||||
|
||||
public PredefinedMap(
|
||||
int xmlResourceId
|
||||
, String name
|
||||
, Size size
|
||||
, MapObject[] eventObjects
|
||||
, MonsterSpawnArea[] spawnAreas
|
||||
, List<String> initiallyActiveMapObjectGroups
|
||||
, boolean isOutdoors
|
||||
, String colorFilter
|
||||
) {
|
||||
this.xmlResourceId = xmlResourceId;
|
||||
this.name = name;
|
||||
this.size = size;
|
||||
this.eventObjects = eventObjects;
|
||||
this.spawnAreas = spawnAreas;
|
||||
this.initiallyActiveMapObjectGroups = initiallyActiveMapObjectGroups;
|
||||
this.activeMapObjectGroups = new LinkedList<String>();
|
||||
this.activeMapObjectGroups.addAll(this.initiallyActiveMapObjectGroups);
|
||||
activateMapObjects();
|
||||
assert(size.width > 0);
|
||||
assert(size.height > 0);
|
||||
this.isOutdoors = isOutdoors;
|
||||
this.initialColorFilter = colorFilter;
|
||||
}
|
||||
|
||||
public final boolean isOutside(final Coord p) { return isOutside(p.x, p.y); }
|
||||
public final boolean isOutside(final int x, final int y) {
|
||||
if (x < 0) return true;
|
||||
if (y < 0) return true;
|
||||
if (x >= size.width) return true;
|
||||
if (y >= size.height) return true;
|
||||
return false;
|
||||
}
|
||||
public final boolean isOutside(final CoordRect area) {
|
||||
if (isOutside(area.topLeft)) return true;
|
||||
if (area.topLeft.x + area.size.width > size.width) return true;
|
||||
if (area.topLeft.y + area.size.height > size.height) return true;
|
||||
return false;
|
||||
}
|
||||
public boolean intersects(CoordRect area) {
|
||||
return new CoordRect(new Coord(0,0), size).intersects(area);
|
||||
}
|
||||
|
||||
public MapObject findEventObject(MapObject.MapObjectType objectType, String name) {
|
||||
for (MapObject o : eventObjects) {
|
||||
if (o.type != objectType) continue;
|
||||
if (!name.equals(o.id)) continue;
|
||||
return o;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public List<MapObject> getActiveEventObjectsAt(final Coord p) {
|
||||
List<MapObject> result = null;
|
||||
for (MapObject o : eventObjects) {
|
||||
if (!o.isActive) continue;
|
||||
if (!o.position.contains(p)) continue;
|
||||
//if (!activeMapObjectGroups.contains(o.group)) continue;
|
||||
if (result == null) result = new ArrayList<MapObject>();
|
||||
result.add(o);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
public boolean hasContainerAt(final Coord p) {
|
||||
for (MapObject o : eventObjects) {
|
||||
if (!o.isActive) continue;
|
||||
if (o.type != MapObject.MapObjectType.container) continue;
|
||||
if (!o.position.contains(p)) continue;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public Monster getMonsterAt(final CoordRect p) {
|
||||
return getMonsterAt(p, null);
|
||||
}
|
||||
public Monster getMonsterAt(final CoordRect p, Monster exceptMe) {
|
||||
for (MonsterSpawnArea a : spawnAreas) {
|
||||
Monster m = a.getMonsterAt(p);
|
||||
if (m != null && (exceptMe == null || exceptMe != m)) return m;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public Monster getMonsterAt(final Coord p) { return getMonsterAt(p.x, p.y); }
|
||||
public Monster getMonsterAt(final int x, final int y) {
|
||||
for (MonsterSpawnArea a : spawnAreas) {
|
||||
Monster m = a.getMonsterAt(x, y);
|
||||
if (m != null) return m;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Monster findSpawnedMonster(final String monsterTypeID) {
|
||||
for (MonsterSpawnArea a : spawnAreas) {
|
||||
Monster m = a.findSpawnedMonster(monsterTypeID);
|
||||
if (m != null) return m;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Loot getBagAt(final Coord p) {
|
||||
for (Loot l : groundBags) {
|
||||
if (l.position.equals(p)) return l;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public Loot getBagOrCreateAt(final Coord position) {
|
||||
Loot b = getBagAt(position);
|
||||
if (b != null) return b;
|
||||
boolean isContainer = hasContainerAt(position);
|
||||
b = new Loot(!isContainer);
|
||||
b.position.set(position);
|
||||
if (isOutside(position)) {
|
||||
if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
|
||||
L.log("WARNING: trying to place bag outside map. Map is " + size.toString() + ", bag tried to place at " + position.toString());
|
||||
}
|
||||
return b;
|
||||
}
|
||||
groundBags.add(b);
|
||||
return b;
|
||||
}
|
||||
public void itemDropped(ItemType itemType, int quantity, Coord position) {
|
||||
Loot l = getBagOrCreateAt(position);
|
||||
l.items.addItem(itemType, quantity);
|
||||
}
|
||||
public void removeGroundLoot(Loot loot) {
|
||||
groundBags.remove(loot);
|
||||
}
|
||||
public void resetForNewGame() {
|
||||
for (MonsterSpawnArea a : spawnAreas) {
|
||||
a.resetForNewGame();
|
||||
}
|
||||
activeMapObjectGroups.clear();
|
||||
activeMapObjectGroups.addAll(initiallyActiveMapObjectGroups);
|
||||
activateMapObjects();
|
||||
resetTemporaryData();
|
||||
groundBags.clear();
|
||||
visited = false;
|
||||
currentColorFilter = initialColorFilter;
|
||||
lastSeenLayoutHash = "";
|
||||
}
|
||||
|
||||
public boolean isRecentlyVisited() {
|
||||
if (lastVisitTime == VISIT_RESET) return false;
|
||||
return (System.currentTimeMillis() - lastVisitTime) < Constants.MAP_UNVISITED_RESPAWN_DURATION_MS;
|
||||
}
|
||||
public void updateLastVisitTime() {
|
||||
lastVisitTime = System.currentTimeMillis();
|
||||
}
|
||||
public void resetTemporaryData() {
|
||||
for(MonsterSpawnArea a : spawnAreas) {
|
||||
if (a.isUnique) a.resetShops();
|
||||
else a.removeAllMonsters();
|
||||
}
|
||||
splatters.clear();
|
||||
lastVisitTime = VISIT_RESET;
|
||||
}
|
||||
public boolean hasResetTemporaryData() {
|
||||
return lastVisitTime == VISIT_RESET;
|
||||
}
|
||||
|
||||
public void createAllContainerLoot() {
|
||||
for (MapObject o : eventObjects) {
|
||||
if (!o.isActive) continue;
|
||||
if (o.type != MapObject.MapObjectType.container) continue;
|
||||
createContainerLoot(o);
|
||||
}
|
||||
}
|
||||
|
||||
public void createContainerLoot(MapObject container) {
|
||||
Loot bag = getBagOrCreateAt(container.position.topLeft);
|
||||
container.dropList.createRandomLoot(bag, null);
|
||||
}
|
||||
|
||||
|
||||
private void activateMapObjects() {
|
||||
for (MapObject o : eventObjects) {
|
||||
o.isActive = activeMapObjectGroups.contains(o.group);
|
||||
}
|
||||
}
|
||||
|
||||
public void activateMapObjectGroup(String group) {
|
||||
if (!activeMapObjectGroups.contains(group)) {
|
||||
activeMapObjectGroups.add(group);
|
||||
for (MapObject o : eventObjects) {
|
||||
if (o.group.equals(group)) {
|
||||
o.isActive = true;
|
||||
if (o.type == MapObjectType.container) createContainerLoot(o);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void deactivateMapObjectGroup(String group) {
|
||||
if (activeMapObjectGroups.contains(group)) {
|
||||
activeMapObjectGroups.remove(group);
|
||||
for (MapObject o : eventObjects) {
|
||||
if (o.group.equals(group)) {
|
||||
o.isActive = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ====== PARCELABLE ===================================================================
|
||||
|
||||
public void readFromParcel(DataInputStream src, WorldContext world, ControllerContext controllers, int fileversion) throws IOException {
|
||||
boolean shouldLoadMapData = true;
|
||||
if (fileversion >= 37) shouldLoadMapData = src.readBoolean();
|
||||
|
||||
int loadedSpawnAreas = 0;
|
||||
if (shouldLoadMapData) {
|
||||
loadedSpawnAreas = src.readInt();
|
||||
for(int i = 0; i < loadedSpawnAreas; ++i) {
|
||||
if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
|
||||
if (i >= this.spawnAreas.length) {
|
||||
L.log("WARNING: Trying to load monsters from savegame in map " + this.name + " for spawn #" + i + ". This will totally fail.");
|
||||
}
|
||||
}
|
||||
if(fileversion >= 43) {
|
||||
//Spawn areas now have unique IDs. Need to check as maps can change.
|
||||
String id = src.readUTF();
|
||||
int j = i;
|
||||
boolean found = false;
|
||||
do {
|
||||
if (this.spawnAreas[j].areaID.equals(id)) {
|
||||
this.spawnAreas[j].readFromParcel(src, world, fileversion);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
j = (j+1)%spawnAreas.length;
|
||||
} while (j != i);
|
||||
if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
|
||||
if (!found) {
|
||||
L.log("WARNING: Trying to load monsters from savegame in map " + this.name + " for spawn #" + id + " but this area cannot be found. This will totally fail.");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.spawnAreas[i].readFromParcel(src, world, fileversion);
|
||||
}
|
||||
}
|
||||
|
||||
activeMapObjectGroups.clear();
|
||||
if(fileversion >= 43) {
|
||||
int activeListLength = src.readInt();
|
||||
for (int i = 0; i < activeListLength; i++) {
|
||||
String activeGroupID = src.readUTF();
|
||||
activeMapObjectGroups.add(activeGroupID);
|
||||
}
|
||||
} else {
|
||||
activeMapObjectGroups.addAll(initiallyActiveMapObjectGroups);
|
||||
}
|
||||
activateMapObjects();
|
||||
|
||||
groundBags.clear();
|
||||
if (fileversion <= 5) return;
|
||||
|
||||
final int size2 = src.readInt();
|
||||
for(int i = 0; i < size2; ++i) {
|
||||
groundBags.add(new Loot(src, world, fileversion));
|
||||
}
|
||||
|
||||
if (fileversion <= 11) return;
|
||||
|
||||
if (fileversion < 37) visited = src.readBoolean();
|
||||
|
||||
if (fileversion <= 15) {
|
||||
if (visited) {
|
||||
lastVisitTime = System.currentTimeMillis();
|
||||
createAllContainerLoot();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (fileversion >= 43) {
|
||||
if (src.readBoolean()) {
|
||||
currentColorFilter = src.readUTF();
|
||||
} else {
|
||||
currentColorFilter = null;
|
||||
}
|
||||
}
|
||||
|
||||
lastVisitTime = src.readLong();
|
||||
|
||||
if (visited) {
|
||||
if (fileversion > 30 && fileversion < 36) {
|
||||
/*int lastVisitVersion = */src.readInt();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
activeMapObjectGroups.clear();
|
||||
activeMapObjectGroups.addAll(initiallyActiveMapObjectGroups);
|
||||
activateMapObjects();
|
||||
}
|
||||
if (fileversion >= 37) {
|
||||
if (fileversion < 41) visited = true;
|
||||
else visited = src.readBoolean();
|
||||
}
|
||||
|
||||
if (fileversion < 36) lastSeenLayoutHash = "";
|
||||
else lastSeenLayoutHash = src.readUTF();
|
||||
|
||||
for(int i = loadedSpawnAreas; i < spawnAreas.length; ++i) {
|
||||
MonsterSpawnArea area = this.spawnAreas[i];
|
||||
if (area.isUnique && visited) controllers.monsterSpawnController.spawnAllInArea(this, null, area, true);
|
||||
else area.resetForNewGame();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean shouldSaveMapData(WorldContext world) {
|
||||
if (!hasResetTemporaryData()) return true;
|
||||
if (this == world.model.currentMap) return true;
|
||||
if (!groundBags.isEmpty()) return true;
|
||||
for (MonsterSpawnArea a : spawnAreas) {
|
||||
if (this.visited && a.isUnique) return true;
|
||||
if (a.isSpawning != a.isSpawningForNewGame) return true;
|
||||
}
|
||||
if (!activeMapObjectGroups.containsAll(initiallyActiveMapObjectGroups)
|
||||
|| !initiallyActiveMapObjectGroups.containsAll(activeMapObjectGroups)) return true;
|
||||
if (currentColorFilter != null) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public void writeToParcel(DataOutputStream dest, WorldContext world) throws IOException {
|
||||
if (shouldSaveMapData(world)) {
|
||||
dest.writeBoolean(true);
|
||||
dest.writeInt(spawnAreas.length);
|
||||
for(MonsterSpawnArea a : spawnAreas) {
|
||||
dest.writeUTF(a.areaID);
|
||||
a.writeToParcel(dest);
|
||||
}
|
||||
dest.writeInt(activeMapObjectGroups.size());
|
||||
for(String s : activeMapObjectGroups) {
|
||||
dest.writeUTF(s);
|
||||
}
|
||||
dest.writeInt(groundBags.size());
|
||||
for(Loot l : groundBags) {
|
||||
l.writeToParcel(dest);
|
||||
}
|
||||
dest.writeBoolean(currentColorFilter != null);
|
||||
if (currentColorFilter != null) dest.writeUTF(currentColorFilter);
|
||||
dest.writeLong(lastVisitTime);
|
||||
} else {
|
||||
dest.writeBoolean(false);
|
||||
}
|
||||
dest.writeBoolean(visited);
|
||||
dest.writeUTF(lastSeenLayoutHash);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,8 +59,10 @@ public final class TMXMapTranslator {
|
||||
assert(m.height > 0);
|
||||
|
||||
boolean isOutdoors = false;
|
||||
String colorFilter = null;
|
||||
for (TMXProperty p : m.properties) {
|
||||
if(p.name.equalsIgnoreCase("outdoors")) isOutdoors = (Integer.parseInt(p.value) != 0);
|
||||
else if(p.name.equalsIgnoreCase("colorfilter")) colorFilter = p.value;
|
||||
else if(AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) L.log("OPTIMIZE: Map " + m.name + " has unrecognized property \"" + p.name + "\".");
|
||||
}
|
||||
|
||||
@@ -212,7 +214,7 @@ public final class TMXMapTranslator {
|
||||
MonsterSpawnArea[] _spawnAreas = new MonsterSpawnArea[spawnAreas.size()];
|
||||
_spawnAreas = spawnAreas.toArray(_spawnAreas);
|
||||
|
||||
result.add(new PredefinedMap(m.xmlResourceId, m.name, mapSize, _eventObjects, _spawnAreas, activeGroups, isOutdoors));
|
||||
result.add(new PredefinedMap(m.xmlResourceId, m.name, mapSize, _eventObjects, _spawnAreas, activeGroups, isOutdoors, colorFilter));
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -347,6 +349,7 @@ public final class TMXMapTranslator {
|
||||
HashSet<Integer> usedTileIDs,
|
||||
SetOfLayerNames layerNames
|
||||
) {
|
||||
|
||||
final MapLayer layerGround = transformMapLayer(layersPerLayerName, layerNames.groundLayerName, srcMap, tileCache, area, usedTileIDs);
|
||||
final MapLayer layerObjects = transformMapLayer(layersPerLayerName, layerNames.objectsLayerName, srcMap, tileCache, area, usedTileIDs);
|
||||
final MapLayer layerAbove = transformMapLayer(layersPerLayerName, layerNames.aboveLayersName, srcMap, tileCache, area, usedTileIDs);
|
||||
|
||||
@@ -1,123 +1,125 @@
|
||||
package com.gpl.rpg.AndorsTrail.resource.tiles;
|
||||
|
||||
import java.lang.ref.Reference;
|
||||
import java.lang.ref.ReferenceQueue;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.util.SparseArray;
|
||||
import android.util.SparseIntArray;
|
||||
|
||||
import com.gpl.rpg.AndorsTrail.util.LruCache;
|
||||
|
||||
public final class TileCache {
|
||||
|
||||
private final ReferenceQueue<Bitmap> gcQueue = new ReferenceQueue<Bitmap>();
|
||||
private ResourceFileTile[] resourceTiles = new ResourceFileTile[1];
|
||||
private final HashMap<String, SparseIntArray> tileIDsPerTilesetAndLocalID = new HashMap<String, SparseIntArray>();
|
||||
private final LruCache<Integer, Bitmap> cache = new LruCache<Integer, Bitmap>(1000);
|
||||
|
||||
public int getMaxTileID() { return resourceTiles.length-1; }
|
||||
public void allocateMaxTileID(int maxTileID) {
|
||||
if (maxTileID <= 0) return;
|
||||
|
||||
ResourceFileTile[] oldArray = resourceTiles;
|
||||
resourceTiles = new ResourceFileTile[maxTileID+1];
|
||||
System.arraycopy(oldArray, 0, resourceTiles, 0, oldArray.length);
|
||||
}
|
||||
public void setTile(int tileID, ResourceFileTileset tileset, int localID) {
|
||||
if (resourceTiles[tileID] == null) resourceTiles[tileID] = new ResourceFileTile(tileset, localID);
|
||||
SparseIntArray tileIDsPerLocalID = tileIDsPerTilesetAndLocalID.get(tileset.tilesetName);
|
||||
if (tileIDsPerLocalID == null) {
|
||||
tileIDsPerLocalID = new SparseIntArray();
|
||||
tileIDsPerTilesetAndLocalID.put(tileset.tilesetName, tileIDsPerLocalID);
|
||||
}
|
||||
tileIDsPerLocalID.put(localID, tileID);
|
||||
}
|
||||
public int getTileID(String tileSetName, int localID) {
|
||||
return tileIDsPerTilesetAndLocalID.get(tileSetName).get(localID);
|
||||
}
|
||||
|
||||
private static final class ResourceFileTile {
|
||||
public final ResourceFileTileset tileset;
|
||||
public final int localID;
|
||||
//public WeakReference<Bitmap> bitmap;
|
||||
public ResourceFileTile(ResourceFileTileset tileset, int localID) {
|
||||
this.tileset = tileset;
|
||||
this.localID = localID;
|
||||
}
|
||||
}
|
||||
|
||||
private void cleanQueue() {
|
||||
System.gc();
|
||||
Reference<? extends Bitmap> ref;
|
||||
while ((ref = gcQueue.poll()) != null) {
|
||||
Bitmap b = ref.get();
|
||||
if (b != null) b.recycle();
|
||||
}
|
||||
}
|
||||
|
||||
public TileCollection loadTilesFor(Collection<Integer> iconIDs, Resources r) { return loadTilesFor(iconIDs, r, null); }
|
||||
public TileCollection loadTilesFor(Collection<Integer> iconIDs, Resources r, TileCollection result) {
|
||||
int maxTileID = 0;
|
||||
HashMap<ResourceFileTileset, SparseArray<ResourceFileTile>> tilesToLoadPerSourceFile = new HashMap<ResourceFileTileset, SparseArray<ResourceFileTile>>();
|
||||
for(int tileID : iconIDs) {
|
||||
ResourceFileTile tile = resourceTiles[tileID];
|
||||
SparseArray<ResourceFileTile> tiles = tilesToLoadPerSourceFile.get(tile.tileset);
|
||||
if (tiles == null) {
|
||||
tiles = new SparseArray<TileCache.ResourceFileTile>();
|
||||
tilesToLoadPerSourceFile.put(tile.tileset, tiles);
|
||||
}
|
||||
tiles.put(tileID, tile);
|
||||
maxTileID = Math.max(maxTileID, tileID);
|
||||
}
|
||||
|
||||
boolean hasLoadedTiles = false;
|
||||
if (result == null) result = new TileCollection(maxTileID);
|
||||
for(Entry<ResourceFileTileset, SparseArray<ResourceFileTile>> e : tilesToLoadPerSourceFile.entrySet()) {
|
||||
TileCutter cutter = null;
|
||||
|
||||
SparseArray<ResourceFileTile> tilesToLoad = e.getValue();
|
||||
for (int i = 0; i < tilesToLoad.size(); ++i) {
|
||||
int tileID = tilesToLoad.keyAt(i);
|
||||
ResourceFileTile tile = tilesToLoad.valueAt(i);
|
||||
|
||||
Bitmap bitmap = cache.get(tileID);
|
||||
|
||||
if (bitmap == null) {
|
||||
if (cutter == null) {
|
||||
if (!hasLoadedTiles) cleanQueue();
|
||||
cutter = new TileCutter(e.getKey(), r);
|
||||
hasLoadedTiles = true;
|
||||
}
|
||||
|
||||
bitmap = cutter.createTile(tile.localID);
|
||||
cache.put(tileID, bitmap);
|
||||
new WeakReference<Bitmap>(bitmap, gcQueue);
|
||||
}
|
||||
result.setBitmap(tileID, bitmap);
|
||||
}
|
||||
|
||||
if (cutter != null) cutter.recycle();
|
||||
}
|
||||
if (hasLoadedTiles) cleanQueue();
|
||||
return result;
|
||||
}
|
||||
|
||||
public Bitmap loadSingleTile(int tileID, Resources r) {
|
||||
cleanQueue();
|
||||
ResourceFileTile tile = resourceTiles[tileID];
|
||||
Bitmap bitmap = cache.get(tileID);
|
||||
if (bitmap != null) return bitmap;
|
||||
|
||||
TileCutter cutter = new TileCutter(tile.tileset, r);
|
||||
Bitmap result = cutter.createTile(tile.localID);
|
||||
cutter.recycle();
|
||||
cache.put(tileID, result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
package com.gpl.rpg.AndorsTrail.resource.tiles;
|
||||
|
||||
import java.lang.ref.Reference;
|
||||
import java.lang.ref.ReferenceQueue;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.util.SparseArray;
|
||||
import android.util.SparseIntArray;
|
||||
|
||||
import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
|
||||
import com.gpl.rpg.AndorsTrail.util.L;
|
||||
import com.gpl.rpg.AndorsTrail.util.LruCache;
|
||||
|
||||
public final class TileCache {
|
||||
|
||||
private final ReferenceQueue<Bitmap> gcQueue = new ReferenceQueue<Bitmap>();
|
||||
private ResourceFileTile[] resourceTiles = new ResourceFileTile[1];
|
||||
private final HashMap<String, SparseIntArray> tileIDsPerTilesetAndLocalID = new HashMap<String, SparseIntArray>();
|
||||
private final LruCache<Integer, Bitmap> cache = new LruCache<Integer, Bitmap>(1000);
|
||||
|
||||
public int getMaxTileID() { return resourceTiles.length-1; }
|
||||
public void allocateMaxTileID(int maxTileID) {
|
||||
if (maxTileID <= 0) return;
|
||||
|
||||
ResourceFileTile[] oldArray = resourceTiles;
|
||||
resourceTiles = new ResourceFileTile[maxTileID+1];
|
||||
System.arraycopy(oldArray, 0, resourceTiles, 0, oldArray.length);
|
||||
}
|
||||
public void setTile(int tileID, ResourceFileTileset tileset, int localID) {
|
||||
if (resourceTiles[tileID] == null) resourceTiles[tileID] = new ResourceFileTile(tileset, localID);
|
||||
SparseIntArray tileIDsPerLocalID = tileIDsPerTilesetAndLocalID.get(tileset.tilesetName);
|
||||
if (tileIDsPerLocalID == null) {
|
||||
tileIDsPerLocalID = new SparseIntArray();
|
||||
tileIDsPerTilesetAndLocalID.put(tileset.tilesetName, tileIDsPerLocalID);
|
||||
}
|
||||
tileIDsPerLocalID.put(localID, tileID);
|
||||
}
|
||||
public int getTileID(String tileSetName, int localID) {
|
||||
return tileIDsPerTilesetAndLocalID.get(tileSetName).get(localID);
|
||||
}
|
||||
|
||||
private static final class ResourceFileTile {
|
||||
public final ResourceFileTileset tileset;
|
||||
public final int localID;
|
||||
//public WeakReference<Bitmap> bitmap;
|
||||
public ResourceFileTile(ResourceFileTileset tileset, int localID) {
|
||||
this.tileset = tileset;
|
||||
this.localID = localID;
|
||||
}
|
||||
}
|
||||
|
||||
private void cleanQueue() {
|
||||
System.gc();
|
||||
Reference<? extends Bitmap> ref;
|
||||
while ((ref = gcQueue.poll()) != null) {
|
||||
Bitmap b = ref.get();
|
||||
if (b != null) b.recycle();
|
||||
}
|
||||
}
|
||||
|
||||
public TileCollection loadTilesFor(Collection<Integer> iconIDs, Resources r) { return loadTilesFor(iconIDs, r, null); }
|
||||
public TileCollection loadTilesFor(Collection<Integer> iconIDs, Resources r, TileCollection result) {
|
||||
int maxTileID = 0;
|
||||
HashMap<ResourceFileTileset, SparseArray<ResourceFileTile>> tilesToLoadPerSourceFile = new HashMap<ResourceFileTileset, SparseArray<ResourceFileTile>>();
|
||||
for(int tileID : iconIDs) {
|
||||
ResourceFileTile tile = resourceTiles[tileID];
|
||||
SparseArray<ResourceFileTile> tiles = tilesToLoadPerSourceFile.get(tile.tileset);
|
||||
if (tiles == null) {
|
||||
tiles = new SparseArray<TileCache.ResourceFileTile>();
|
||||
tilesToLoadPerSourceFile.put(tile.tileset, tiles);
|
||||
}
|
||||
tiles.put(tileID, tile);
|
||||
maxTileID = Math.max(maxTileID, tileID);
|
||||
}
|
||||
|
||||
boolean hasLoadedTiles = false;
|
||||
if (result == null) result = new TileCollection(maxTileID);
|
||||
for(Entry<ResourceFileTileset, SparseArray<ResourceFileTile>> e : tilesToLoadPerSourceFile.entrySet()) {
|
||||
TileCutter cutter = null;
|
||||
|
||||
SparseArray<ResourceFileTile> tilesToLoad = e.getValue();
|
||||
for (int i = 0; i < tilesToLoad.size(); ++i) {
|
||||
int tileID = tilesToLoad.keyAt(i);
|
||||
ResourceFileTile tile = tilesToLoad.valueAt(i);
|
||||
|
||||
Bitmap bitmap = cache.get(tileID);
|
||||
|
||||
if (bitmap == null) {
|
||||
if (cutter == null) {
|
||||
if (!hasLoadedTiles) cleanQueue();
|
||||
cutter = new TileCutter(e.getKey(), r);
|
||||
hasLoadedTiles = true;
|
||||
}
|
||||
|
||||
bitmap = cutter.createTile(tile.localID);
|
||||
cache.put(tileID, bitmap);
|
||||
new WeakReference<Bitmap>(bitmap, gcQueue);
|
||||
}
|
||||
result.setBitmap(tileID, bitmap);
|
||||
}
|
||||
|
||||
if (cutter != null) cutter.recycle();
|
||||
}
|
||||
if (hasLoadedTiles) cleanQueue();
|
||||
return result;
|
||||
}
|
||||
|
||||
public Bitmap loadSingleTile(int tileID, Resources r) {
|
||||
cleanQueue();
|
||||
ResourceFileTile tile = resourceTiles[tileID];
|
||||
Bitmap bitmap = cache.get(tileID);
|
||||
if (bitmap != null) return bitmap;
|
||||
|
||||
TileCutter cutter = new TileCutter(tile.tileset, r);
|
||||
Bitmap result = cutter.createTile(tile.localID);
|
||||
cutter.recycle();
|
||||
cache.put(tileID, result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
package com.gpl.rpg.AndorsTrail.util;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
|
||||
|
||||
public final class L {
|
||||
private static final String TAG = "AndorsTrail";
|
||||
|
||||
public static void log(String s) {
|
||||
if (AndorsTrailApplication.DEVELOPMENT_DEBUGMESSAGES) {
|
||||
Log.d(TAG, s);
|
||||
}
|
||||
}
|
||||
}
|
||||
package com.gpl.rpg.AndorsTrail.util;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
|
||||
|
||||
public final class L {
|
||||
private static final String TAG = "AndorsTrail";
|
||||
|
||||
public static void log(String s) {
|
||||
if (AndorsTrailApplication.DEVELOPMENT_DEBUGMESSAGES) {
|
||||
Log.w(TAG, s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user