Merge branch 'master' into sdl2
This commit is contained in:
commit
fedf2478d3
55 changed files with 314 additions and 117 deletions
|
@ -93,6 +93,9 @@ Version 1.13.1+dev:
|
|||
variable ($recruited_unit_random_variation).
|
||||
* Fixed unit [resistance] and [jamming_costs] not being considered for sync
|
||||
check.
|
||||
* Fixed problems with slow/poison/petrify sounds (bug #23024) and made the
|
||||
sounds play automatically when the status is inflicted in combat, instead
|
||||
of being played by attack animations.
|
||||
|
||||
Version 1.13.1:
|
||||
* Security fixes:
|
||||
|
|
|
@ -309,7 +309,6 @@ function ca_fast_attack_utils.damage_rating_unit(attacker_info, defender_info, a
|
|||
value = value * (1. + xp_bonus * xp_weight)
|
||||
|
||||
local rating = fractional_damage * value
|
||||
--print('damage, fractional_damage, value, rating', attacker_info.id, damage, fractional_damage, value, rating)
|
||||
|
||||
return rating
|
||||
end
|
||||
|
@ -417,8 +416,6 @@ function ca_fast_attack_utils.attack_rating(attacker_infos, defender_info, dsts,
|
|||
-- This is a number equivalent to 'aggression' in the default AI (but not numerically equal)
|
||||
local rating = defender_rating - attacker_rating * own_value_weight + extra_rating
|
||||
|
||||
--print('rating, attacker_rating, defender_rating, extra_rating:', rating, attacker_rating, defender_rating, extra_rating)
|
||||
|
||||
return rating, attacker_rating, defender_rating, extra_rating
|
||||
end
|
||||
|
||||
|
|
|
@ -27,8 +27,10 @@ function ca_fast_combat:evaluation(ai, cfg, self)
|
|||
if (not self.data.fast_combat_units) or (not self.data.fast_combat_units[1]) then
|
||||
self.data.fast_combat_units = wesnoth.get_units {
|
||||
side = wesnoth.current.side,
|
||||
canrecruit = 'no',
|
||||
{ "and", filter_own }
|
||||
}
|
||||
|
||||
if (not self.data.fast_combat_units[1]) then return 0 end
|
||||
|
||||
-- For speed reasons, we'll go through the arrays from the end, so they are sorted backwards
|
||||
|
@ -105,9 +107,6 @@ function ca_fast_combat:evaluation(ai, cfg, self)
|
|||
|
||||
local acceptable_attack = FAU.is_acceptable_attack(attacker_rating, defender_rating, own_value_weight)
|
||||
|
||||
--print(unit.id, target.id, rating, attacker_rating, defender_rating, extra_rating)
|
||||
--print(' -->' , own_value_weight, defender_rating/attacker_rating, acceptable_attack)
|
||||
|
||||
if acceptable_attack and (rating > max_rating) then
|
||||
max_rating, best_target, best_dst = rating, target, attack.dst
|
||||
end
|
||||
|
|
186
data/ai/micro_ais/cas/ca_fast_combat_leader.lua
Normal file
186
data/ai/micro_ais/cas/ca_fast_combat_leader.lua
Normal file
|
@ -0,0 +1,186 @@
|
|||
local H = wesnoth.require "lua/helper.lua"
|
||||
local AH = wesnoth.require "ai/lua/ai_helper.lua"
|
||||
local FAU = wesnoth.require "ai/micro_ais/cas/ca_fast_attack_utils.lua"
|
||||
local LS = wesnoth.require "lua/location_set.lua"
|
||||
|
||||
local ca_fast_combat_leader = {}
|
||||
|
||||
function ca_fast_combat_leader:evaluation(ai, cfg, self)
|
||||
-- Some parts of this are very similar to ca_fast_combat.lua.
|
||||
-- However, for speed reasons we really want this to be a separate CA, so
|
||||
-- that the (more expensive) calculations for keeping the leader safe only
|
||||
-- get done once, when all other Fast MAI CAs are entirely done.
|
||||
|
||||
leader_weight = (cfg and cfg.leader_weight) or 2
|
||||
leader_attack_max_units = (cfg and cfg.leader_attack_max_units) or 3
|
||||
|
||||
self.data.move_cache = { turn = wesnoth.current.turn }
|
||||
self.data.gamedata = FAU.gamedata_setup()
|
||||
|
||||
local filter_own = cfg.filter
|
||||
local filter_enemy = cfg.filter_second
|
||||
if (not filter_own) and (not filter_enemy) then
|
||||
local ai_tag = H.get_child(wesnoth.sides[wesnoth.current.side].__cfg, 'ai')
|
||||
for aspect in H.child_range(ai_tag, 'aspect') do
|
||||
if (aspect.id == 'attacks') then
|
||||
local facet = H.get_child(aspect, 'facet')
|
||||
if facet then
|
||||
filter_own = H.get_child(facet, 'filter_own')
|
||||
filter_enemy = H.get_child(facet, 'filter_enemy')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local leader = wesnoth.get_units {
|
||||
side = wesnoth.current.side,
|
||||
canrecruit = 'yes',
|
||||
{ "and", filter_own }
|
||||
}[1]
|
||||
|
||||
if (not leader) then return 0 end
|
||||
if (leader.attacks_left == 0) or (not H.get_child(leader.__cfg, 'attack')) then return 0 end
|
||||
|
||||
local excluded_enemies_map = LS.create()
|
||||
|
||||
-- Exclude enemies not matching [filter_enemy]
|
||||
if filter_enemy then
|
||||
local excluded_enemies = wesnoth.get_units {
|
||||
{ "filter_side", { { "enemy_of", { side = wesnoth.current.side } } } },
|
||||
{ "not", filter_enemy }
|
||||
}
|
||||
|
||||
for _,e in ipairs(excluded_enemies) do
|
||||
excluded_enemies_map:insert(e.x, e.y)
|
||||
end
|
||||
end
|
||||
|
||||
-- Exclude hidden enemies, except if attack_hidden_enemies=yes is set in [micro_ai] tag
|
||||
if (not cfg.attack_hidden_enemies) then
|
||||
local hidden_enemies = wesnoth.get_units {
|
||||
{ "filter_side", { { "enemy_of", { side = wesnoth.current.side } } } },
|
||||
{ "filter_vision", { side = wesnoth.current.side, visible = 'no' } }
|
||||
}
|
||||
|
||||
for _,e in ipairs(hidden_enemies) do
|
||||
excluded_enemies_map:insert(e.x, e.y)
|
||||
end
|
||||
end
|
||||
|
||||
local aggression = ai.get_aggression()
|
||||
if (aggression > 1) then aggression = 1 end
|
||||
local own_value_weight = 1. - aggression
|
||||
|
||||
-- Get the locations to be avoided
|
||||
local avoid_map = FAU.get_avoid_map(cfg)
|
||||
|
||||
-- Enemy power and number maps
|
||||
-- Currently, the power is simply the summed hitpoints of all enemies that
|
||||
-- can get to a hex
|
||||
local enemies = wesnoth.get_units {
|
||||
{ "filter_side", { { "enemy_of", { side = wesnoth.current.side } } } }
|
||||
}
|
||||
|
||||
local enemy_power_map = LS.create()
|
||||
local enemy_number_map = LS.create()
|
||||
|
||||
for _,enemy in ipairs(enemies) do
|
||||
-- Only need to consider enemies that are close enough
|
||||
if (H.distance_between(leader.x, leader.y, enemy.x, enemy.y) <= (enemy.max_moves + leader.max_moves + 1)) then
|
||||
enemy_power = enemy.hitpoints
|
||||
|
||||
local old_moves = enemy.moves
|
||||
enemy.moves = enemy.max_moves
|
||||
local reach = wesnoth.find_reach(enemy)
|
||||
enemy.moves = old_moves
|
||||
|
||||
for _,loc in ipairs(reach) do
|
||||
enemy_power_map:insert(
|
||||
loc[1], loc[2],
|
||||
(enemy_power_map:get(loc[1], loc[2]) or 0) + enemy_power
|
||||
)
|
||||
enemy_number_map:insert(
|
||||
loc[1], loc[2],
|
||||
(enemy_number_map:get(loc[1], loc[2]) or 0) + 1
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local leader_info = FAU.get_unit_info(leader, self.data.gamedata)
|
||||
local leader_copy = FAU.get_unit_copy(leader.id, self.data.gamedata)
|
||||
|
||||
local attacks = AH.get_attacks({ leader }, { include_occupied = cfg.include_occupied_attack_hexes })
|
||||
|
||||
if (#attacks > 0) then
|
||||
local max_rating, best_target, best_dst = -9e99
|
||||
for _,attack in ipairs(attacks) do
|
||||
if (not excluded_enemies_map:get(attack.target.x, attack.target.y))
|
||||
and (not avoid_map:get(attack.dst.x, attack.dst.y))
|
||||
then
|
||||
-- First check if the threat against the leader at this hex
|
||||
-- is acceptable
|
||||
local acceptable_attack = true
|
||||
for xa,ya in H.adjacent_tiles(attack.dst.x, attack.dst.y) do
|
||||
local enemy_power = enemy_power_map:get(xa, ya) or 0
|
||||
local enemy_number = enemy_number_map:get(xa, ya) or 0
|
||||
|
||||
if (enemy_power * leader_weight > leader.hitpoints)
|
||||
or (enemy_number > leader_attack_max_units)
|
||||
then
|
||||
acceptable_attack = false
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if acceptable_attack then
|
||||
local target = wesnoth.get_unit(attack.target.x, attack.target.y)
|
||||
local target_info = FAU.get_unit_info(target, self.data.gamedata)
|
||||
|
||||
local att_stat, def_stat = FAU.battle_outcome(
|
||||
leader_copy, target, { attack.dst.x, attack.dst.y },
|
||||
leader_info, target_info, self.data.gamedata, self.data.move_cache
|
||||
)
|
||||
|
||||
local rating, attacker_rating, defender_rating, extra_rating = FAU.attack_rating(
|
||||
{ leader_info }, target_info, { { attack.dst.x, attack.dst.y } },
|
||||
{ att_stat }, def_stat, self.data.gamedata,
|
||||
{
|
||||
own_value_weight = own_value_weight,
|
||||
leader_weight = cfg.leader_weight
|
||||
}
|
||||
)
|
||||
|
||||
acceptable_attack = FAU.is_acceptable_attack(attacker_rating, defender_rating, own_value_weight)
|
||||
|
||||
if acceptable_attack and (rating > max_rating) then
|
||||
max_rating, best_target, best_dst = rating, target, attack.dst
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if best_target then
|
||||
self.data.leader = leader
|
||||
self.data.fast_target, self.data.fast_dst = best_target, best_dst
|
||||
return cfg.ca_score
|
||||
end
|
||||
end
|
||||
|
||||
return 0
|
||||
end
|
||||
|
||||
function ca_fast_combat_leader:execution(ai, cfg, self)
|
||||
local leader = self.data.leader
|
||||
AH.movefull_outofway_stopunit(ai, leader, self.data.fast_dst.x, self.data.fast_dst.y)
|
||||
|
||||
if (not leader) or (not leader.valid) then return end
|
||||
if (not self.data.fast_target) or (not self.data.fast_target.valid) then return end
|
||||
if (H.distance_between(leader.x, leader.y, self.data.fast_target.x, self.data.fast_target.y) ~= 1) then return end
|
||||
|
||||
AH.checked_attack(ai, leader, self.data.fast_target)
|
||||
|
||||
self.data.leader = nil
|
||||
end
|
||||
|
||||
return ca_fast_combat_leader
|
|
@ -461,13 +461,14 @@ function wesnoth.wml_actions.micro_ai(cfg)
|
|||
elseif (cfg.ai_type == 'fast_ai') then
|
||||
optional_keys = {
|
||||
"attack_hidden_enemies", "avoid", "dungeon_mode", "filter", "filter_second",
|
||||
"include_occupied_attack_hexes", "leader_weight", "move_cost_factor",
|
||||
"include_occupied_attack_hexes", "leader_attack_max_units", "leader_weight", "move_cost_factor",
|
||||
"weak_units_first", "skip_combat_ca", "skip_move_ca"
|
||||
}
|
||||
CA_parms = {
|
||||
ai_id = 'mai_fast',
|
||||
{ ca_id = 'combat', location = CA_path .. 'ca_fast_combat.lua', score = 100000 },
|
||||
{ ca_id = 'move', location = CA_path .. 'ca_fast_move.lua', score = 20000 }
|
||||
{ ca_id = 'move', location = CA_path .. 'ca_fast_move.lua', score = 20000 },
|
||||
{ ca_id = 'combat_leader', location = CA_path .. 'ca_fast_combat_leader.lua', score = 19900 }
|
||||
}
|
||||
|
||||
-- Also need to delete/add some default CAs
|
||||
|
@ -533,9 +534,8 @@ function wesnoth.wml_actions.micro_ai(cfg)
|
|||
}
|
||||
else
|
||||
for i,parm in ipairs(CA_parms) do
|
||||
if (parm.ca_id == 'combat') then
|
||||
if (parm.ca_id == 'combat') or (parm.ca_id == 'combat_leader') then
|
||||
table.remove(CA_parms, i)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -65,7 +65,6 @@
|
|||
[frame]
|
||||
image="units/monsters/kraken.png:100"
|
||||
[/frame]
|
||||
{SOUND:POISON}
|
||||
[/attack_anim]
|
||||
|
||||
# tentacles hit south----------------------------------------------
|
||||
|
|
|
@ -75,7 +75,6 @@
|
|||
[attack_sound_frame]
|
||||
sound=entangle.wav
|
||||
[/attack_sound_frame]
|
||||
{SOUND:SLOW}
|
||||
|
||||
[frame]
|
||||
image="units/wose-shaman.png"
|
||||
|
|
|
@ -79,7 +79,6 @@
|
|||
image=units/annalist-ranged[1~2].png:[150,300]
|
||||
[/frame]
|
||||
{SOUND:HIT_AND_MISS hatchet.wav hatchet-miss.wav -200}
|
||||
{SOUND:SLOW}
|
||||
[frame]
|
||||
image="units/annalist.png:50"
|
||||
[/frame]
|
||||
|
|
|
@ -83,7 +83,6 @@
|
|||
image=units/loremaster-ranged[1~2].png:[150,300]
|
||||
[/frame]
|
||||
{SOUND:HIT_AND_MISS hatchet.wav hatchet-miss.wav -200}
|
||||
{SOUND:SLOW}
|
||||
[frame]
|
||||
image="units/loremaster.png:50"
|
||||
[/frame]
|
||||
|
|
|
@ -84,7 +84,6 @@
|
|||
image=units/witness-ranged[1~2].png:[150,300]
|
||||
[/frame]
|
||||
{SOUND:HIT_AND_MISS hatchet.wav hatchet-miss.wav -200}
|
||||
{SOUND:SLOW}
|
||||
[frame]
|
||||
image="units/witness.png:50"
|
||||
[/frame]
|
||||
|
|
|
@ -103,7 +103,6 @@
|
|||
[attack_sound_frame]
|
||||
sound=entangle.wav
|
||||
[/attack_sound_frame]
|
||||
{SOUND:SLOW}
|
||||
[/attack_anim]
|
||||
[attack_anim]
|
||||
[filter_attack]
|
||||
|
|
|
@ -55,7 +55,6 @@
|
|||
image="units/elves-desert/hunter-ranged-[1~4].png:[125*4]"
|
||||
[/frame]
|
||||
{SOUND:HIT_AND_MISS hatchet.wav hatchet-miss.wav -375}
|
||||
{SOUND:SLOW}
|
||||
[/attack_anim]
|
||||
[attack_anim]
|
||||
[filter_attack]
|
||||
|
|
|
@ -57,7 +57,6 @@
|
|||
image="units/elves-desert/prowler.png:[125*4]"
|
||||
[/frame]
|
||||
{SOUND:HIT_AND_MISS hatchet.wav hatchet-miss.wav -375}
|
||||
{SOUND:SLOW}
|
||||
[/attack_anim]
|
||||
[attack_anim]
|
||||
[filter_attack]
|
||||
|
|
|
@ -56,7 +56,6 @@
|
|||
image="units/elves-desert/sentinel.png:300"
|
||||
[/frame]
|
||||
{SOUND:HIT_AND_MISS hatchet.wav hatchet-miss.wav -300}
|
||||
{SOUND:SLOW}
|
||||
[/attack_anim]
|
||||
[attack_anim]
|
||||
[filter_attack]
|
||||
|
|
|
@ -79,7 +79,6 @@
|
|||
[attack_sound_frame]
|
||||
sound=entangle.wav
|
||||
[/attack_sound_frame]
|
||||
{SOUND:SLOW}
|
||||
[frame]
|
||||
image="units/elves-desert/shaman.png:50"
|
||||
[/frame]
|
||||
|
|
|
@ -108,7 +108,6 @@
|
|||
[attack_sound_frame]
|
||||
sound=entangle.wav
|
||||
[/attack_sound_frame]
|
||||
{SOUND:SLOW}
|
||||
[/attack_anim]
|
||||
[attack_anim]
|
||||
[filter_attack]
|
||||
|
|
|
@ -98,7 +98,6 @@
|
|||
image=units/elves-desert/kaleh.png:300
|
||||
[/frame]
|
||||
{SOUND:HIT_AND_MISS hatchet.wav hatchet-miss.wav -300}
|
||||
{SOUND:SLOW}
|
||||
[/attack_anim]
|
||||
[/effect]
|
||||
) {VARIANT_NAME}}
|
||||
|
|
|
@ -51,7 +51,6 @@
|
|||
image=units/elves-desert/nym-ranged-[1~3].png:[100*3]
|
||||
[/frame]
|
||||
{SOUND:HIT_AND_MISS hatchet.wav hatchet-miss.wav -300}
|
||||
{SOUND:SLOW}
|
||||
[/attack_anim]
|
||||
[attack_anim]
|
||||
[filter_attack]
|
||||
|
|
|
@ -72,7 +72,6 @@
|
|||
[/frame]
|
||||
|
||||
{SOUND:HIT_AND_MISS throwing-knife.ogg throwing-knife-miss.ogg -100}
|
||||
{SOUND:POISON}
|
||||
[/attack_anim]
|
||||
[attack_anim]
|
||||
[filter_attack]
|
||||
|
|
|
@ -103,7 +103,6 @@ The chief ability of Druids lies in healing, and it is for this skill that they
|
|||
[attack_sound_frame]
|
||||
sound=entangle.wav
|
||||
[/attack_sound_frame]
|
||||
{SOUND:SLOW}
|
||||
[/attack_anim]
|
||||
[attack_anim]
|
||||
[filter_attack]
|
||||
|
|
|
@ -91,7 +91,6 @@
|
|||
[attack_sound_frame]
|
||||
sound=entangle.wav
|
||||
[/attack_sound_frame]
|
||||
{SOUND:SLOW}
|
||||
[/attack_anim]
|
||||
[attack_anim]
|
||||
[filter_attack]
|
||||
|
|
|
@ -78,7 +78,6 @@ The healing abilities of the elves are also remarkable, and of capital use in ba
|
|||
[attack_sound_frame]
|
||||
sound=entangle.wav
|
||||
[/attack_sound_frame]
|
||||
{SOUND:SLOW}
|
||||
[frame]
|
||||
image="units/elves-wood/shaman.png:50"
|
||||
[/frame]
|
||||
|
|
|
@ -107,7 +107,6 @@
|
|||
[attack_sound_frame]
|
||||
sound=entangle.wav
|
||||
[/attack_sound_frame]
|
||||
{SOUND:SLOW}
|
||||
[/attack_anim]
|
||||
[attack_anim]
|
||||
[filter_attack]
|
||||
|
|
|
@ -94,7 +94,6 @@ Those able to do so are roughly titled as ‘sorceresses’ by other races; and
|
|||
[attack_sound_frame]
|
||||
sound=entangle.wav
|
||||
[/attack_sound_frame]
|
||||
{SOUND:SLOW}
|
||||
[/attack_anim]
|
||||
[attack_anim]
|
||||
[filter_attack]
|
||||
|
|
|
@ -96,7 +96,6 @@
|
|||
[attack_sound_frame]
|
||||
sound=entangle.wav
|
||||
[/attack_sound_frame]
|
||||
{SOUND:SLOW}
|
||||
[/attack_anim]
|
||||
[attack_anim]
|
||||
[filter_attack]
|
||||
|
|
|
@ -68,7 +68,6 @@ The claws of a wolf are not generally regarded as being the more dangerous parts
|
|||
image="units/goblins/direwolver-moving.png:100"
|
||||
[/frame]
|
||||
{SOUND:HIT_AND_MISS claws.ogg {SOUND_LIST:MISS} -100}
|
||||
{SOUND:POISON}
|
||||
[frame]
|
||||
image="units/goblins/direwolver-attack.png:150"
|
||||
[/frame]
|
||||
|
|
|
@ -79,7 +79,6 @@
|
|||
[frame]
|
||||
image="units/goblins/pillager.png:175"
|
||||
[/frame]
|
||||
{SOUND:SLOW}
|
||||
[/attack_anim]
|
||||
[attack_anim]
|
||||
[filter_attack]
|
||||
|
|
|
@ -62,7 +62,6 @@
|
|||
image="units/human-outlaws/assassin-throwknife[1~2].png:[250,150]"
|
||||
[/frame]
|
||||
{SOUND:HIT_AND_MISS throwing-knife.ogg throwing-knife-miss.ogg -150}
|
||||
{SOUND:POISON}
|
||||
[frame]
|
||||
image="units/human-outlaws/assassin.png:100"
|
||||
[/frame]
|
||||
|
|
|
@ -67,6 +67,5 @@
|
|||
[/frame]
|
||||
|
||||
{SOUND:HIT_AND_MISS mace.wav {SOUND_LIST:MISS} -100}
|
||||
{SOUND:SLOW}
|
||||
[/attack_anim]
|
||||
[/unit_type]
|
||||
|
|
|
@ -74,6 +74,5 @@
|
|||
[/frame]
|
||||
|
||||
{SOUND:HIT_AND_MISS mace.wav {SOUND_LIST:MISS} -100}
|
||||
{SOUND:SLOW}
|
||||
[/attack_anim]
|
||||
[/unit_type]
|
||||
|
|
|
@ -68,6 +68,5 @@
|
|||
[/frame]
|
||||
|
||||
{SOUND:HIT_AND_MISS mace.wav {SOUND_LIST:MISS} -100}
|
||||
{SOUND:SLOW}
|
||||
[/attack_anim]
|
||||
[/unit_type]
|
||||
|
|
|
@ -56,7 +56,6 @@ Mermen often find themselves in a standoff with land-based enemies; the merfolk
|
|||
image="units/merfolk/entangler.png:75"
|
||||
[/frame]
|
||||
{SOUND:HIT_AND_MISS net.wav {SOUND_LIST:MISS} -75}
|
||||
{SOUND:SLOW}
|
||||
[frame]
|
||||
image="units/merfolk/entangler.png:175"
|
||||
[/frame]
|
||||
|
|
|
@ -68,7 +68,6 @@ The effectiveness of this method led to the development of smaller, weighted net
|
|||
[frame]
|
||||
image="units/merfolk/netcaster.png:175"
|
||||
[/frame]
|
||||
{SOUND:SLOW}
|
||||
[/attack_anim]
|
||||
[attack_anim]
|
||||
[filter_attack]
|
||||
|
|
|
@ -60,7 +60,6 @@
|
|||
image="units/monsters/cuttlefish-ranged-[1~6].png:100"
|
||||
[/frame]
|
||||
{SOUND:HIT_AND_MISS squishy-strike.wav squishy-miss.wav -100}
|
||||
{SOUND:POISON}
|
||||
[/attack_anim]
|
||||
[attack_anim]
|
||||
[filter_attack]
|
||||
|
|
|
@ -72,7 +72,6 @@
|
|||
image="units/monsters/scorpion/scorpion.png:200"
|
||||
[/frame]
|
||||
{SOUND:HIT_AND_MISS spear.ogg {SOUND_LIST:MISS} -100}
|
||||
{SOUND:POISON}
|
||||
[frame]
|
||||
image="units/monsters/scorpion/scorpion.png:100"
|
||||
[/frame]
|
||||
|
|
|
@ -58,7 +58,6 @@
|
|||
image="units/monsters/spider-ranged-[1~7,3~1].png:75"
|
||||
[/frame]
|
||||
{SOUND:HIT_AND_MISS net.wav {SOUND_LIST:MISS} -100}
|
||||
{SOUND:SLOW}
|
||||
[/attack_anim]
|
||||
[attack_anim]
|
||||
start_time=-400
|
||||
|
@ -69,6 +68,5 @@
|
|||
image="units/monsters/spider-melee-[1~13].png:50"
|
||||
[/frame]
|
||||
{SOUND:HIT_AND_MISS bite.ogg {SOUND_LIST:MISS} -50}
|
||||
{SOUND:POISON}
|
||||
[/attack_anim]
|
||||
[/unit_type]
|
||||
|
|
|
@ -60,7 +60,6 @@
|
|||
image=units/monsters/water-serpent-attack-se-[1~6].png:[150*3,200,100,150]
|
||||
[/frame]
|
||||
{SOUND:HIT_AND_MISS bite-small.ogg {SOUND_LIST:MISS} -50}
|
||||
{SOUND:POISON}
|
||||
[/attack_anim]
|
||||
[attack_anim]
|
||||
[filter_attack]
|
||||
|
@ -78,7 +77,6 @@
|
|||
[frame]
|
||||
image=units/monsters/water-serpent-attack-s-[5~6].png:[100,150]
|
||||
[/frame]
|
||||
{SOUND:POISON}
|
||||
[/attack_anim]
|
||||
[attack_anim]
|
||||
[filter_attack]
|
||||
|
@ -92,7 +90,6 @@
|
|||
image=units/monsters/water-serpent-attack-ne-[1~6].png:[150*3,200,100,150]
|
||||
[/frame]
|
||||
{SOUND:HIT_AND_MISS bite-small.ogg {SOUND_LIST:MISS} -50}
|
||||
{SOUND:POISON}
|
||||
[/attack_anim]
|
||||
[attack_anim]
|
||||
[filter_attack]
|
||||
|
@ -109,6 +106,5 @@
|
|||
[frame]
|
||||
image=units/monsters/water-serpent-attack-n-[5~6].png:[100,150]
|
||||
[/frame]
|
||||
{SOUND:POISON}
|
||||
[/attack_anim]
|
||||
[/unit_type]
|
||||
|
|
|
@ -72,7 +72,6 @@
|
|||
image="units/orcs/assassin-ranged[1,2].png:100"
|
||||
[/frame]
|
||||
{SOUND:HIT_AND_MISS throwing-knife.ogg throwing-knife-miss.ogg -150}
|
||||
{SOUND:POISON}
|
||||
[/attack_anim]
|
||||
[attack_anim]
|
||||
[filter_attack]
|
||||
|
|
|
@ -94,7 +94,6 @@
|
|||
[/frame]
|
||||
|
||||
{SOUND:HIT_AND_MISS throwing-knife.ogg throwing-knife-miss.ogg -100}
|
||||
{SOUND:POISON}
|
||||
[/attack_anim]
|
||||
[attack_anim]
|
||||
[filter_attack]
|
||||
|
|
|
@ -59,7 +59,6 @@
|
|||
image="units/orcs/slayer-ranged[1~2].png:[50,100]"
|
||||
[/frame]
|
||||
{SOUND:HIT_AND_MISS throwing-knife.ogg throwing-knife-miss.ogg -150}
|
||||
{SOUND:POISON}
|
||||
[/attack_anim]
|
||||
[attack_anim]
|
||||
[filter_attack]
|
||||
|
|
|
@ -44,6 +44,5 @@
|
|||
image="units/undead/ghast-attack-[1~6].png:[100,150,100*4]"
|
||||
[/frame]
|
||||
{SOUND:HIT_AND_MISS bite.ogg {SOUND_LIST:MISS} -350}
|
||||
{SOUND:POISON}
|
||||
[/attack_anim]
|
||||
[/unit_type]
|
||||
|
|
|
@ -45,7 +45,6 @@ It is because of such things that necromancy is condemned with an almost primal
|
|||
image="units/undead/ghoul-attack-[1~4].png:[75*2,100,75]"
|
||||
[/frame]
|
||||
{SOUND:HIT_AND_MISS claws.ogg {SOUND_LIST:MISS} -125}
|
||||
{SOUND:POISON}
|
||||
[frame]
|
||||
image="units/undead/ghoul.png:75"
|
||||
[/frame]
|
||||
|
|
|
@ -43,7 +43,6 @@
|
|||
image="units/undead/necrophage.png:50"
|
||||
[/frame]
|
||||
{SOUND:HIT_AND_MISS claws.ogg {SOUND_LIST:MISS} -125}
|
||||
{SOUND:POISON}
|
||||
[frame]
|
||||
image="units/undead/necrophage-attack-[1~4].png:[75*2,100,75]"
|
||||
[/frame]
|
||||
|
|
|
@ -95,6 +95,12 @@
|
|||
game_user_leave = "leave.wav"
|
||||
ready_for_start = "bell.wav"
|
||||
game_has_begun = "gamestart.ogg"
|
||||
|
||||
[status]
|
||||
slowed="slowed.wav"
|
||||
poisoned="poison.ogg"
|
||||
petrified="petrified.ogg"
|
||||
[/status]
|
||||
[/sounds]
|
||||
|
||||
fog_prefix="terrain/fog/fog"
|
||||
|
|
|
@ -3538,12 +3538,7 @@ unplagueable: $wml_unit.status.unplagueable"
|
|||
code=<<
|
||||
local args = ...
|
||||
local unit = wesnoth.get_unit(args.x1, args.y1)
|
||||
local raw_msg = "Unit statuses in LUA:\
|
||||
\
|
||||
not_living: %s\
|
||||
unpoisonable: %s\
|
||||
undrainable: %s\
|
||||
unplagueable: %s"
|
||||
local raw_msg = "Unit statuses in Lua:\n\nnot_living: %s\nunpoisonable: %s\nundrainable: %s\nunplagueable: %s"
|
||||
local msg = string.format(raw_msg, unit.status.not_living, unit.status.unpoisonable, unit.status.undrainable, unit.status.unplagueable)
|
||||
wesnoth.wml_actions.message({speaker = "narrator", message = msg})
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ if sys.version_info.major >= 3:
|
|||
else: # we are on Python 2
|
||||
import Queue
|
||||
# tkinter modules
|
||||
import tkFont as font # in Py3 it's tkinter.font
|
||||
from Tkinter import *
|
||||
from tkMessageBox import *
|
||||
from tkFileDialog import *
|
||||
|
@ -150,7 +151,10 @@ mouse pointer stays on the widget for more than 500 ms."""
|
|||
background="#ffffe1", # background color used on Windows
|
||||
borderwidth=1,
|
||||
relief=SOLID,
|
||||
padding=1)
|
||||
padding=1,
|
||||
# Tk has a bunch of predefined fonts
|
||||
# use the one specific for tooltips
|
||||
font=font.nametofont("TkTooltipFont"))
|
||||
self.label.pack()
|
||||
self.overrideredirect(True)
|
||||
self.widget.bind("<Enter>",self.preshow)
|
||||
|
@ -192,6 +196,9 @@ mouse pointer stays on the widget for more than 500 ms."""
|
|||
if self.preshow_id:
|
||||
self.after_cancel(self.preshow_id)
|
||||
self.preshow_id=None
|
||||
def set_text(self,text):
|
||||
self.label.configure(text=text)
|
||||
self.update_idletasks()
|
||||
|
||||
class Popup(Toplevel):
|
||||
def __init__(self,parent,tool,thread):
|
||||
|
@ -820,14 +827,18 @@ class WmlindentTab(Frame):
|
|||
column=0,
|
||||
sticky=W,
|
||||
padx=10)
|
||||
self.tooltip_normal=Tooltip(self.radio_normal,
|
||||
"Perform file conversion")
|
||||
self.radio_dryrun=Radiobutton(self.mode_frame,
|
||||
text="Dry run\nDo not perform changes",
|
||||
text="Dry run",
|
||||
variable=self.mode_variable,
|
||||
value=1)
|
||||
self.radio_dryrun.grid(row=1,
|
||||
column=0,
|
||||
sticky=W,
|
||||
padx=10)
|
||||
self.tooltip_dryrun=Tooltip(self.radio_dryrun,
|
||||
"Do not perform changes")
|
||||
self.verbosity_frame=LabelFrame(self,
|
||||
text="Verbosity level")
|
||||
self.verbosity_frame.grid(row=0,
|
||||
|
@ -914,46 +925,40 @@ class MainFrame(Frame):
|
|||
column=0,
|
||||
sticky=E+W)
|
||||
self.run_button=Button(self.buttonbox,
|
||||
text="Run wmllint",
|
||||
image=ICONS['run'],
|
||||
compound=LEFT,
|
||||
width=15, # to avoid changing size when callback is called
|
||||
command=self.on_run_wmllint)
|
||||
self.run_button.pack(side=LEFT,
|
||||
padx=5,
|
||||
pady=5)
|
||||
self.run_tooltip=Tooltip(self.run_button,"Run wmllint")
|
||||
self.save_button=Button(self.buttonbox,
|
||||
text="Save as text...",
|
||||
image=ICONS['save'],
|
||||
compound=LEFT,
|
||||
command=self.on_save)
|
||||
self.save_button.pack(side=LEFT,
|
||||
padx=5,
|
||||
pady=5)
|
||||
self.save_tooltip=Tooltip(self.save_button,"Save as text...")
|
||||
self.clear_button=Button(self.buttonbox,
|
||||
text="Clear output",
|
||||
image=ICONS['clear'],
|
||||
compound=LEFT,
|
||||
command=self.on_clear)
|
||||
self.clear_button.pack(side=LEFT,
|
||||
padx=5,
|
||||
pady=5)
|
||||
self.clear_tooltip=Tooltip(self.clear_button,"Clear output")
|
||||
self.about_button=Button(self.buttonbox,
|
||||
text="About...",
|
||||
image=ICONS['about'],
|
||||
compound=LEFT,
|
||||
command=self.on_about)
|
||||
self.about_button.pack(side=LEFT,
|
||||
padx=5,
|
||||
pady=5)
|
||||
self.about_tooltip=Tooltip(self.about_button,"About...")
|
||||
self.exit_button=Button(self.buttonbox,
|
||||
text="Exit",
|
||||
image=ICONS['exit'],
|
||||
compound=LEFT,
|
||||
command=self.on_quit)
|
||||
self.exit_button.pack(side=RIGHT,
|
||||
padx=5,
|
||||
pady=5)
|
||||
self.exit_tooltip=Tooltip(self.exit_button,"Exit")
|
||||
self.dir_variable=StringVar()
|
||||
self.dir_frame=SelectDirectory(self,
|
||||
textvariable=self.dir_variable)
|
||||
|
@ -1027,11 +1032,14 @@ class MainFrame(Frame):
|
|||
# the order of the tabs is pretty obvious
|
||||
active_tab=self.notebook.index(self.notebook.select())
|
||||
if active_tab==0:
|
||||
self.run_button.configure(text="Run wmllint",command=self.on_run_wmllint)
|
||||
self.run_tooltip.set_text("Run wmllint")
|
||||
self.run_button.configure(command=self.on_run_wmllint)
|
||||
elif active_tab==1:
|
||||
self.run_button.configure(text="Run wmlscope",command=self.on_run_wmlscope)
|
||||
self.run_tooltip.set_text("Run wmlscope")
|
||||
self.run_button.configure(command=self.on_run_wmlscope)
|
||||
elif active_tab==2:
|
||||
self.run_button.configure(text="Run wmlindent",command=self.on_run_wmlindent)
|
||||
self.run_tooltip.set_text("Run wmlindent")
|
||||
self.run_button.configure(command=self.on_run_wmlindent)
|
||||
|
||||
def on_run_wmllint(self):
|
||||
# first of all, check if we have something to run wmllint on it
|
||||
|
|
|
@ -271,11 +271,11 @@ filemoves = {
|
|||
("orc-small-hit.wav", "orc-small-hit-1.ogg"),
|
||||
),
|
||||
"1.3.3" : (
|
||||
("sounds/dragonstick-hit.ogg", "sounds/dragonstick-hit-1.ogg"),
|
||||
("sounds/dragonstick-miss.ogg", "sounds/dragonstick-miss.wav"),
|
||||
("sounds/dragonstick-hit.ogg", "sounds/dragonstick-hit-1.ogg"),
|
||||
("sounds/dragonstick-miss.ogg", "sounds/dragonstick-miss.wav"),
|
||||
),
|
||||
"1.3.4" : (
|
||||
# This release changed from numeric to string palette IDs
|
||||
# This release changed from numeric to string palette IDs
|
||||
("RC(magenta>1)", "RC(magenta>red)"),
|
||||
("RC(magenta>2)", "RC(magenta>blue)"),
|
||||
("RC(magenta>3)", "RC(magenta>green)"),
|
||||
|
@ -297,14 +297,14 @@ filemoves = {
|
|||
),
|
||||
# 1.35 was an aborted release
|
||||
"1.3.6" : (
|
||||
("Soul Shooter", "Banebow"),
|
||||
("Halbardier" , "Halberdier"),
|
||||
("Soul Shooter", "Banebow"),
|
||||
("Halbardier" , "Halberdier"),
|
||||
),
|
||||
"1.3.9" : (
|
||||
("Outlaw Ranger", "Ranger"),
|
||||
("Outlaw Ranger", "Ranger"),
|
||||
),
|
||||
"1.3.14" : (
|
||||
("{AMLA_TOUGH 3}", "{AMLA_DEFAULT}"),
|
||||
("{AMLA_TOUGH 3}", "{AMLA_DEFAULT}"),
|
||||
),
|
||||
# An empty sentinel value at end is required.
|
||||
"trunk" : (),
|
||||
|
@ -393,21 +393,21 @@ def neighborhood(x, y, map_):
|
|||
odd = (x) % 2
|
||||
adj = [map_[y][x]];
|
||||
if x > 0:
|
||||
adj.append(map_[y][x-1])
|
||||
adj.append(map_[y][x-1])
|
||||
if x < len(map_[y])-1:
|
||||
adj.append(map_[y][x+1])
|
||||
adj.append(map_[y][x+1])
|
||||
if y > 0:
|
||||
adj.append(map_[y-1][x])
|
||||
adj.append(map_[y-1][x])
|
||||
if y < len(map_)-1:
|
||||
adj.append(map_[y+1][x])
|
||||
adj.append(map_[y+1][x])
|
||||
if x > 0 and y > 0 and not odd:
|
||||
adj.append(map_[y-1][x-1])
|
||||
adj.append(map_[y-1][x-1])
|
||||
if x < len(map_[y])-1 and y > 0 and not odd:
|
||||
adj.append(map_[y-1][x+1])
|
||||
adj.append(map_[y-1][x+1])
|
||||
if x > 0 and y < len(map_)-1 and odd:
|
||||
adj.append(map_[y+1][x-1])
|
||||
adj.append(map_[y+1][x-1])
|
||||
if x < len(map_[y])-1 and y < len(map_)-1 and odd:
|
||||
adj.append(map_[y+1][x+1])
|
||||
adj.append(map_[y+1][x+1])
|
||||
return adj
|
||||
|
||||
def maptransform1(filename, baseline, inmap, y):
|
||||
|
@ -466,7 +466,7 @@ conversion2 = {
|
|||
re.compile(r"(?<!\^)Vs\b") : "Ss^Vhs",
|
||||
re.compile(r"(?<!\^)Vsm\b") : "Ss^Vm",
|
||||
re.compile(r"(?<!\^)Xm\b") : "Mm^Xm",
|
||||
re.compile(r"\bGg\^Vwm\b") : "Gg^Vh", # This is the 1.3.13 -> 1.3.14 one
|
||||
re.compile(r"\bGg\^Vwm\b") : "Gg^Vh", # This is the 1.3.13 -> 1.3.14 one
|
||||
}
|
||||
|
||||
# Global changes meant to be done on all lines
|
||||
|
@ -557,7 +557,7 @@ notepairs = (
|
|||
("{ABILITY_FEEDING}", "{SPECIAL_NOTES_FEEDING}"),
|
||||
("{WEAPON_SPECIAL_BERSERK}", "{SPECIAL_NOTES_BERSERK}"),
|
||||
("{WEAPON_SPECIAL_BACKSTAB}", "{SPECIAL_NOTES_BACKSTAB}"),
|
||||
("{WEAPON_SPECIAL_PLAGUE", "{SPECIAL_NOTES_PLAGUE}"), # No } deliberately
|
||||
("{WEAPON_SPECIAL_PLAGUE", "{SPECIAL_NOTES_PLAGUE}"), # No } deliberately
|
||||
("{WEAPON_SPECIAL_SLOW}", "{SPECIAL_NOTES_SLOW}"),
|
||||
("{WEAPON_SPECIAL_STONE}", "{SPECIAL_NOTES_STONE}"),
|
||||
("{WEAPON_SPECIAL_MARKSMAN}", "{SPECIAL_NOTES_MARKSMAN}"),
|
||||
|
@ -785,7 +785,7 @@ def sanity_check(filename, lines):
|
|||
print('"%s", line %d: side number %s is out of sequence' %
|
||||
(filename, i+1, value))
|
||||
except ValueError:
|
||||
pass # Ignore ill-formed integer literals
|
||||
pass # Ignore ill-formed integer literals
|
||||
except TypeError:
|
||||
pass
|
||||
# Consistency-check the description attributes in [side], [unit], [recall],
|
||||
|
@ -842,11 +842,11 @@ def sanity_check(filename, lines):
|
|||
print('"%s", line %d: extraneous space in translatable string' %
|
||||
(filename, i+1))
|
||||
# Check correctness of translation marks and descriptions
|
||||
if key.startswith("#"): # FIXME: parse_attribute is confused.
|
||||
if key.startswith("#"): # FIXME: parse_attribute is confused.
|
||||
pass
|
||||
elif key == 'letter': # May be led with _s for void
|
||||
elif key == 'letter': # May be led with _s for void
|
||||
pass
|
||||
elif key == 'name': # FIXME: check this someday
|
||||
elif key == 'name': # FIXME: check this someday
|
||||
pass
|
||||
elif key in ("message", "user_description", "story", "note", "text", "summary", "caption", "label", "unit_description") and not value.startswith("$"):
|
||||
if not has_tr_mark:
|
||||
|
@ -897,7 +897,7 @@ def sanity_check(filename, lines):
|
|||
textdomains.append(i+1)
|
||||
if not textdomains:
|
||||
print('"%s", line 1: no textdomain string' % filename)
|
||||
elif textdomains[0] == 1: # Multiples are OK if first is on line 1
|
||||
elif textdomains[0] == 1: # Multiples are OK if first is on line 1
|
||||
pass
|
||||
elif len(textdomains) > 1:
|
||||
print('"%s", line %d: multiple textdomain strings on lines %s' %
|
||||
|
@ -1493,16 +1493,16 @@ def hack_syntax(filename, lines):
|
|||
radius_danger = False
|
||||
to_indent = []
|
||||
no_indent = []
|
||||
insideElem = 0
|
||||
insideElem = 0
|
||||
for i in scopeIter:
|
||||
elem = i.element
|
||||
if elem in ("[and]", "[or]", "[not]"):
|
||||
radius_danger = True
|
||||
no_indent.extend(txt+'\n' for txt in i.text.splitlines())
|
||||
insideElem += 1
|
||||
elif insideElem:
|
||||
if elem in ("[/and]", "[/or]", "[/not]"):
|
||||
insideElem -= 1
|
||||
insideElem += 1
|
||||
elif insideElem:
|
||||
if elem in ("[/and]", "[/or]", "[/not]"):
|
||||
insideElem -= 1
|
||||
no_indent.extend(txt+'\n' for txt in i.text.splitlines())
|
||||
elif elem in ("variable=", "side=", "count=", "adjacent="):
|
||||
no_indent.extend(txt+'\n' for txt in i.text.splitlines())
|
||||
|
@ -1513,7 +1513,7 @@ def hack_syntax(filename, lines):
|
|||
if radius_danger:
|
||||
lines = lines[:startline] + [wspace + "[and]\n"] + to_indent +[
|
||||
wspace + "[/and]\n"] + no_indent + lines[scopeIter.lineno:]
|
||||
radius_pos.lines = lines
|
||||
radius_pos.lines = lines
|
||||
modcount += 1
|
||||
#backup to rescan
|
||||
radius_pos.seek(startline-1)
|
||||
|
@ -1684,7 +1684,7 @@ class maptransform_error:
|
|||
def __repr__(self):
|
||||
return '"%s", line %d: %s' % (self.infile, self.inline, self.type)
|
||||
|
||||
tagstack = [] # For tracking tag nesting
|
||||
tagstack = [] # For tracking tag nesting
|
||||
|
||||
def outermap(func, inmap):
|
||||
"Apply a transformation based on neighborhood to the outermost ring."
|
||||
|
@ -1888,7 +1888,7 @@ def translator(filename, mapxforms, textxform, versions):
|
|||
if not unbalanced:
|
||||
fields = newline.split("#")
|
||||
trimmed = fields[0]
|
||||
destringed = re.sub('"[^"]*"', '', trimmed) # Ignore string literals
|
||||
destringed = re.sub('"[^"]*"', '', trimmed) # Ignore string literals
|
||||
comment = ""
|
||||
if len(fields) > 1:
|
||||
comment = fields[1]
|
||||
|
@ -2002,7 +2002,7 @@ def allcfgfiles(dir_):
|
|||
for name in files:
|
||||
if interesting(os.path.join(root, name)):
|
||||
datafiles.append(os.path.join(root, name))
|
||||
datafiles.sort() # So diffs for same campaigns will cluster in reports
|
||||
datafiles.sort() # So diffs for same campaigns will cluster in reports
|
||||
return [os.path.normpath(elem) for elem in datafiles]
|
||||
|
||||
def help():
|
||||
|
@ -2092,7 +2092,7 @@ if __name__ == '__main__':
|
|||
# Compute the series of version upgrades to perform, and describe it.
|
||||
versions = sorted([key for key in filemoves.keys()])
|
||||
# Relies on 'older' sorting before trunk
|
||||
versions = [versions[-2]] + versions[:-2] + [versions[-1]] # Move 'older' to front
|
||||
versions = [versions[-2]] + versions[:-2] + [versions[-1]] # Move 'older' to front
|
||||
if oldversion in versions:
|
||||
versions = versions[versions.index(oldversion):]
|
||||
else:
|
||||
|
|
|
@ -977,29 +977,36 @@ namespace {
|
|||
if (update_display_)
|
||||
{
|
||||
std::ostringstream float_text;
|
||||
std::vector<std::string> extra_hit_sounds;
|
||||
if (hits)
|
||||
{
|
||||
const unit &defender_unit = defender.get_unit();
|
||||
if (attacker_stats->poisons && !defender_unit.get_state(unit::STATE_POISONED)) {
|
||||
float_text << (defender_unit.gender() == unit_race::FEMALE ?
|
||||
_("female^poisoned") : _("poisoned")) << '\n';
|
||||
|
||||
extra_hit_sounds.push_back(game_config::sounds::status::poisoned);
|
||||
}
|
||||
|
||||
if (attacker_stats->slows && !defender_unit.get_state(unit::STATE_SLOWED)) {
|
||||
float_text << (defender_unit.gender() == unit_race::FEMALE ?
|
||||
_("female^slowed") : _("slowed")) << '\n';
|
||||
|
||||
extra_hit_sounds.push_back(game_config::sounds::status::slowed);
|
||||
}
|
||||
|
||||
if (attacker_stats->petrifies) {
|
||||
float_text << (defender_unit.gender() == unit_race::FEMALE ?
|
||||
_("female^petrified") : _("petrified")) << '\n';
|
||||
|
||||
extra_hit_sounds.push_back(game_config::sounds::status::petrified);
|
||||
}
|
||||
}
|
||||
|
||||
unit_display::unit_attack(game_display::get_singleton(), *resources::gameboard,
|
||||
attacker.loc_, defender.loc_, damage,
|
||||
*attacker_stats->weapon, defender_stats->weapon,
|
||||
abs_n, float_text.str(), drains_damage, "");
|
||||
abs_n, float_text.str(), drains_damage, "", &extra_hit_sounds);
|
||||
}
|
||||
|
||||
bool dies = defender.get_unit().take_hit(damage);
|
||||
|
|
|
@ -166,6 +166,12 @@ namespace game_config
|
|||
menu_expand = "expand.wav",
|
||||
menu_contract = "contract.wav",
|
||||
menu_select = "select.wav";
|
||||
|
||||
namespace status {
|
||||
std::string poisoned = "poison.ogg",
|
||||
slowed = "slowed.wav",
|
||||
petrified = "petrified.ogg";
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WESNOTH_PATH
|
||||
|
@ -315,6 +321,13 @@ namespace game_config
|
|||
if (s.has_attribute("game_user_leave")) game_user_leave = s["game_user_leave"].str();
|
||||
if (s.has_attribute("ready_for_start")) ready_for_start = s["ready_for_start"].str();
|
||||
if (s.has_attribute("game_has_begun")) game_has_begun = s["game_has_begun"].str();
|
||||
|
||||
if(const config & ss = s.child("status")) {
|
||||
using namespace game_config::sounds::status;
|
||||
if (ss.has_attribute("poisoned")) poisoned = ss["poisoned"].str();
|
||||
if (ss.has_attribute("slowed")) slowed = ss["slowed"].str();
|
||||
if (ss.has_attribute("petrified")) petrified = ss["petrified"].str();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -152,6 +152,9 @@ namespace game_config
|
|||
game_has_begun;
|
||||
extern const std::string button_press, checkbox_release, slider_adjust,
|
||||
menu_expand, menu_contract, menu_select;
|
||||
namespace status {
|
||||
extern std::string poisoned, slowed, petrified;
|
||||
}
|
||||
}
|
||||
|
||||
void load_config(const config &cfg);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Copyright (C) 2015 - 2015 by David White <dave@whitevine.net>
|
||||
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
|
||||
Copyright (C) 2015 by the Battle for Wesnoth Project
|
||||
<http://www.wesnoth.org/>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -21,6 +21,7 @@
|
|||
|
||||
int quit_confirmation::count_ = 0;
|
||||
bool quit_confirmation::open_ = false;
|
||||
|
||||
void quit_confirmation::quit()
|
||||
{
|
||||
if(count_ != 0 && display::get_singleton() && !open_)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Copyright (C) 2015 - 2015 by David White <dave@whitevine.net>
|
||||
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
|
||||
Copyright (C) 2015 by the Battle for Wesnoth Project
|
||||
<http://www.wesnoth.org/>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -19,16 +19,28 @@ class CVideo;
|
|||
|
||||
#include <cassert>
|
||||
|
||||
/// Any object of this type will prevent the game from quitting immediately, instad a confirmation dialog will pop up when attepmting to close.
|
||||
/**
|
||||
* Implements a quit confirmation dialog.
|
||||
*
|
||||
* Any object of this type will prevent the game from quitting immediately.
|
||||
* Instead, a confirmation dialog will pop up when attempting to close.
|
||||
*/
|
||||
class quit_confirmation
|
||||
{
|
||||
public:
|
||||
quit_confirmation() { ++count_; }
|
||||
quit_confirmation(const quit_confirmation&) { ++count_; }
|
||||
~quit_confirmation() { --count_; assert(count_ >= 0); }
|
||||
/// Shows the quit confirmation if needed, throws CVideo::quit to exit.
|
||||
|
||||
/**
|
||||
* Shows the quit confirmation if needed.
|
||||
*
|
||||
* @throws CVideo::quit If the user chooses to quit or no prompt was
|
||||
* displayed.
|
||||
*/
|
||||
static void quit();
|
||||
static void quit(CVideo& video );
|
||||
|
||||
private:
|
||||
static int count_;
|
||||
static bool open_;
|
||||
|
|
|
@ -592,7 +592,7 @@ void unit_animation::fill_initial_animations( std::vector<unit_animation> & anim
|
|||
animations.back().event_ = utils::split("poisoned");
|
||||
animations.back().unit_anim_.override(0,300,particule::NO_CYCLE,"","0:30,0.5:30,0:30,0.5:30,0:30,0.5:30,0:30,0.5:30,0:30",display::rgb(0,255,0));
|
||||
animations.back().sub_anims_["_poison_sound"] = particule();
|
||||
animations.back().sub_anims_["_poison_sound"].add_frame(1,frame_builder().sound("poison.ogg"),true);
|
||||
animations.back().sub_anims_["_poison_sound"].add_frame(1,frame_builder().sound(game_config::sounds::status::poisoned),true);
|
||||
|
||||
}
|
||||
|
||||
|
@ -705,7 +705,7 @@ void unit_animation::add_anims( std::vector<unit_animation> & animations, const
|
|||
anim["value"] = anim["damage"];
|
||||
animations.push_back(unit_animation(anim));
|
||||
animations.back().sub_anims_["_poison_sound"] = particule();
|
||||
animations.back().sub_anims_["_poison_sound"].add_frame(1,frame_builder().sound("poison.ogg"),true);
|
||||
animations.back().sub_anims_["_poison_sound"].add_frame(1,frame_builder().sound(game_config::sounds::status::poisoned),true);
|
||||
}
|
||||
|
||||
add_simple_anim(animations, cfg, "pre_movement_anim", "pre_movement", display::LAYER_UNIT_MOVE_DEFAULT);
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "log.hpp"
|
||||
#include "mouse_events.hpp"
|
||||
#include "resources.hpp"
|
||||
#include "sound.hpp"
|
||||
#include "terrain_filter.hpp"
|
||||
#include "unit.hpp"
|
||||
#include "unit_animation_component.hpp"
|
||||
|
@ -573,7 +574,7 @@ void unit_die(const map_location& loc, unit& loser,
|
|||
void unit_attack(display * disp, game_board & board,
|
||||
const map_location& a, const map_location& b, int damage,
|
||||
const attack_type& attack, const attack_type* secondary_attack,
|
||||
int swing,std::string hit_text,int drain_amount,std::string att_text)
|
||||
int swing,std::string hit_text,int drain_amount,std::string att_text, const std::vector<std::string>* extra_hit_sounds)
|
||||
{
|
||||
if(!disp ||disp->video().update_locked() || disp->video().faked() ||
|
||||
(disp->fogged(a) && disp->fogged(b)) || preferences::show_combat() == false) {
|
||||
|
@ -653,7 +654,15 @@ void unit_attack(display * disp, game_board & board,
|
|||
animator.start_animations();
|
||||
animator.wait_until(0);
|
||||
int damage_left = damage;
|
||||
bool extra_hit_sounds_played = false;
|
||||
while(damage_left > 0 && !animator.would_end()) {
|
||||
if(!extra_hit_sounds_played && extra_hit_sounds != NULL) {
|
||||
BOOST_FOREACH (std::string hit_sound, *extra_hit_sounds) {
|
||||
sound::play_sound(hit_sound);
|
||||
}
|
||||
extra_hit_sounds_played = true;
|
||||
}
|
||||
|
||||
int step_left = (animator.get_end_time() - animator.get_animation_time() )/50;
|
||||
if(step_left < 1) step_left = 1;
|
||||
int removed_hp = damage_left/step_left ;
|
||||
|
|
|
@ -117,7 +117,7 @@ void unit_sheath_weapon( const map_location& loc, unit* u=NULL, const attack_typ
|
|||
void unit_attack(display * disp, game_board & board, //TODO: Would be nice if this could be purely a display function and defer damage dealing to its caller
|
||||
const map_location& a, const map_location& b, int damage,
|
||||
const attack_type& attack, const attack_type* secondary_attack,
|
||||
int swing, std::string hit_text, int drain_amount, std::string att_text);
|
||||
int swing, std::string hit_text, int drain_amount, std::string att_text, const std::vector<std::string>* extra_hit_sounds=NULL);
|
||||
|
||||
|
||||
void unit_recruited(const map_location& loc,
|
||||
|
|
Loading…
Add table
Reference in a new issue