[Scummvm-git-logs] scummvm master -> 1b26c60841452baee1e9495275f5d3852f5e99fc
mduggan
noreply at scummvm.org
Mon Dec 18 06:41:39 UTC 2023
This automated email contains information about 6 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
11d5b7724a ULTIMA: ULTIMA6: Make map_line_hit_check also return pre-hit x/y
611986a9c2 ULTIMA: ULTIMA6: Ranged attack rework
12da032467 ULTIMA: ULTIMA6: Fix triple crossbow extra projectile targeting
0c5f74b1b4 ULTIMA: ULTIMA6: Fix boomerang origin coordinates when returning
de64a96598 ULTIMA: ULTIMA6: Fix projectile animation destination coordinates
1b26c60841 ULTIMA: ULTIMA6: Fix placement of thrown weapons on map
Commit: 11d5b7724a5ae74bb6dbae179cec3d0da543be63
https://github.com/scummvm/scummvm/commit/11d5b7724a5ae74bb6dbae179cec3d0da543be63
Author: PushmePullyu (127053144+PushmePullyu at users.noreply.github.com)
Date: 2023-12-18T17:41:33+11:00
Commit Message:
ULTIMA: ULTIMA6: Make map_line_hit_check also return pre-hit x/y
This is in preparation for a ranged attack / projectile rework.
Changed paths:
engines/ultima/nuvie/core/map.cpp
engines/ultima/nuvie/core/map.h
engines/ultima/nuvie/script/script.cpp
diff --git a/engines/ultima/nuvie/core/map.cpp b/engines/ultima/nuvie/core/map.cpp
index 4c88f50c592..8a35d7453a3 100644
--- a/engines/ultima/nuvie/core/map.cpp
+++ b/engines/ultima/nuvie/core/map.cpp
@@ -750,6 +750,8 @@ bool Map::lineTest(int start_x, int start_y, int end_x, int end_y, uint8 level,
uint32 count;
int xtile = start_x;
int ytile = start_y;
+ int xtile_prev = xtile;
+ int ytile_prev = ytile;
if (deltax >= deltay) {
@@ -786,11 +788,16 @@ bool Map::lineTest(int start_x, int start_y, int end_x, int end_y, uint8 level,
for (uint32 i = 0; i < count; i++) {
// only test for collision if tile coordinates have changed
if ((scale_factor_log2 == 0 || x >> scale_factor_log2 != xtile || y >> scale_factor_log2 != ytile)) {
+ xtile_prev = xtile;
+ ytile_prev = ytile;
xtile = x >> scale_factor_log2; // scale back down to tile
ytile = y >> scale_factor_log2; // space if necessary
// test the current location
- if ((i >= skip) && (testIntersection(xtile, ytile, level, flags, Result, excluded_obj) == true))
+ if ((i >= skip) && (testIntersection(xtile, ytile, level, flags, Result, excluded_obj) == true)) {
+ Result.pre_hit_x = xtile_prev;
+ Result.pre_hit_y = ytile_prev;
return true;
+ }
}
if (d < 0) {
diff --git a/engines/ultima/nuvie/core/map.h b/engines/ultima/nuvie/core/map.h
index de9f7a63a1b..1be68e9e219 100644
--- a/engines/ultima/nuvie/core/map.h
+++ b/engines/ultima/nuvie/core/map.h
@@ -68,6 +68,8 @@ public:
int hit_x; // x coord where object / actor was hit
int hit_y; // y coord where object / actor was hit
+ int pre_hit_x;
+ int pre_hit_y;
uint8 hit_level; // map level where object / actor was hit
Actor *hitActor;
Obj *hitObj;
diff --git a/engines/ultima/nuvie/script/script.cpp b/engines/ultima/nuvie/script/script.cpp
index 57a0c232f27..a8d79669c6e 100644
--- a/engines/ultima/nuvie/script/script.cpp
+++ b/engines/ultima/nuvie/script/script.cpp
@@ -3153,14 +3153,15 @@ static int nscript_map_line_test(lua_State *L) {
/***
Returns the first point on a line between x,y and x1, y1 where a missile boundary tile is crossed
-If no boundary tiles are crossed on the line then x1, y1 are returned
+Additionally returns the point checked before the hit
+If no boundary tiles are crossed on the line then x1, y1 are returned for both points
@function map_line_hit_check
@int x
@int y
@int x1
@int y1
@int z
- at treturn int,int an x,y coord
+ at treturn int,int,int,int x,y coords
@within map
*/
static int nscript_map_line_hit_check(lua_State *L) {
@@ -3178,12 +3179,17 @@ static int nscript_map_line_hit_check(lua_State *L) {
if (map->lineTest(x, y, x1, y1, level, LT_HitMissileBoundary, result, 0, nullptr, true)) {
lua_pushinteger(L, result.hit_x);
lua_pushinteger(L, result.hit_y);
+ lua_pushinteger(L, result.pre_hit_x);
+ lua_pushinteger(L, result.pre_hit_y);
} else {
lua_pushinteger(L, x1);
lua_pushinteger(L, y1);
+ // no collision, return starting coordinates again instead of pre_hit_x/y
+ lua_pushinteger(L, x1);
+ lua_pushinteger(L, y1);
}
- return 2;
+ return 4;
}
/***
Commit: 611986a9c28a9815e9d03035c12b3466667874d7
https://github.com/scummvm/scummvm/commit/611986a9c28a9815e9d03035c12b3466667874d7
Author: PushmePullyu (127053144+PushmePullyu at users.noreply.github.com)
Date: 2023-12-18T17:41:33+11:00
Commit Message:
ULTIMA: ULTIMA6: Ranged attack rework
Make ranged attack behavior match the original game more closely.
Fixes several inaccuracies in targeting and handling of projectiles.
Changed paths:
devtools/create_ultima/files/ultima6/scripts/u6/actor.lua
diff --git a/devtools/create_ultima/files/ultima6/scripts/u6/actor.lua b/devtools/create_ultima/files/ultima6/scripts/u6/actor.lua
index 67c6264428c..e63751eaa2b 100644
--- a/devtools/create_ultima/files/ultima6/scripts/u6/actor.lua
+++ b/devtools/create_ultima/files/ultima6/scripts/u6/actor.lua
@@ -1456,48 +1456,39 @@ function actor_attack(attacker, target_x, target_y, target_z, weapon, foe)
local hit_actor = actor_combat_hit_check(attacker, foe, weapon)
local num_bolts
- local missed_target = false
+ local coll_tiles
if is_range_weapon == true then
- --FIXME might need to get new foe here.
- target_x, target_y = map_line_hit_check(attacker.x, attacker.y, target_x, target_y, attacker.z)
-
- local failed_line_check
- if foe ~= nil and (foe.x ~= target_x or foe.y ~= target_y) then
- hit_actor = false
- failed_line_check = true
- else
- failed_line_check = false
- end
-
- if hit_actor == false and failed_line_check == false then
- if foe ~= nil then
+ -- Get new target coordinates if the attack roll failed
+ -- This is done before collision checking, which means even blocked targets can cause a miss
+ -- Attacks on empty tiles alway hit
+ if hit_actor == false and foe ~= nil then
target_x = target_x + random(0, 2) - 1
target_y = target_y + random(0, 2) - 1
- local new_foe = map_get_actor(target_x, target_y, attacker.z)
- if new_foe ~= foe then -- make sure multi-tile actors don't get attacked again on a miss
- foe = new_foe
- hit_actor = actor_combat_hit_check(attacker, foe, weapon)
- end
- end
end
if weapon_obj_n == 0x32 then --triple crossbow
num_bolts = Actor.inv_get_obj_total_qty(attacker, 0x38)
- --dgb("total num_bolts = "..num_bolts.."\n")
if num_bolts > 3 then num_bolts = 3 end
+ else
+ num_bolts = 1
end
- if failed_line_check == false then
- --FIXME might need to get new foe here.
- target_x, target_y = map_line_hit_check(attacker.x, attacker.y, target_x, target_y, attacker.z)
+ -- Handle collision checking, projectile animation,
+ -- ammo removal/placement on map and certain special effects
+ coll_tiles = combat_range_weapon_1D5F9(attacker, target_x, target_y, target_z, weapon, num_bolts)
- if foe ~= nil and (foe.x ~= target_x or foe.y ~= target_y) then
- hit_actor = false -- leaving off line check bool since triple bolts should probably do damage
- end
- end
- combat_range_weapon_1D5F9(attacker, target_x, target_y, target_z, foe, weapon)
+ -- For each projectile, coll_tiles now contains the new target tile
+ -- coordinates after collision checking and the foe on that tile (or nil if no actor/obj)
+ -- For convenience:
+ foe = coll_tiles[1].foe
+
+ -- If the first attack was a miss, do another attack roll
+ -- It is possible to roll against the same target that was missed on the previous try a second time
+ if hit_actor == false then
+ hit_actor = actor_combat_hit_check(attacker, foe, weapon)
+ end
else --standard weapon
if actor_find_max_xy_distance(attacker, player_loc.x, player_loc.y) < 6 then
@@ -1508,40 +1499,24 @@ function actor_attack(attacker, target_x, target_y, target_z, weapon, foe)
if weapon_obj_n == 0x32 then --triple crossbow
- local off = ((attacker.y - target_y + 5) * 11) + (attacker.x - target_x + 5)
local i
- for i=1,num_bolts do
+ -- Do attack roll for the extra projectiles and deal damage to each target hit
+ for i=1,num_bolts do
if i > 1 then
- --dgb("num_bolts = "..num_bolts.." off = "..off.." target_x = "..target_x.." target_y = "..target_y.."attacker.x = "..attacker.x.." attacker.y = "..attacker.y.."\n\n")
- local t = g_projectile_offset_tbl[i-1][off+1]
-
- foe = map_get_actor(target_x + movement_offset_x_tbl[t+1], target_y + movement_offset_y_tbl[t+1], player_loc.z)
- --dgb("new_x = "..target_x + movement_offset_x_tbl[t+1].." new_y = "..target_y + movement_offset_y_tbl[t+1].."\n");
- if failed_line_check == true then
- hit_actor = false
- else
- target_x, target_y = map_line_hit_check(attacker.x, attacker.y, target_x, target_y, attacker.z)
- if foe ~= nil and foe.x == target_x and foe.y == target_y then
- hit_actor = actor_combat_hit_check(attacker, foe, weapon);
- else
- hit_actor = false
- end
- end
+ foe = coll_tiles[i].foe
+ hit_actor = actor_combat_hit_check(attacker, foe, weapon)
end
-
if hit_actor == true then
- --dgb("triple xbow hit actor dmg = "..dmg.."\n");
- actor_take_hit(attacker, foe, dmg);
- if g_avatar_died == true then
- return
+ if foe ~= nil and foe.obj_n ~= attacker.obj_n then actor_take_hit(attacker, foe, dmg) end
+ if g_avatar_died == true then --TODO: Is this really needed?
+ return
end
end
-
end
- else
-
- if hit_actor == true then
+ return
+ else --not triple crossbow
+ if hit_actor == true and foe ~= nil and attacker.obj_n ~= foe.obj_n then
local actor_base = actor_tbl[foe.obj_n]
if actor_base ~= nil and actor_base[14] == 1 -- takes half dmg
@@ -1568,26 +1543,61 @@ function actor_attack(attacker, target_x, target_y, target_z, weapon, foe)
end
-function combat_range_weapon_1D5F9(attacker, target_x, target_y, target_z, foe, weapon)
+function combat_range_weapon_1D5F9(attacker, target_x, target_y, target_z, weapon, num_bolts)
+ -- Handles projectiles:
+ -- 1. Collision checking
+ -- 2. Animation
+ -- 3. Ammo removal
+ -- 4. Placement on map (throwing weapons)
+ -- 5. Zu Ylem sleep effect
+ -- Returns new target tiles/foes after collision checking (The original used globals for this)
local weapon_obj_n = weapon.obj_n
local random = math.random
+ local coll_tiles = {} --collision tile and foe for each projectile
+ local pre_coll_tiles = {} --tile traversed before the collision occurred for each projectile
+ local foe
+ local targets
- if weapon_obj_n == 0x32 then --triple cross bow
+ --set up targets table
+ if weapon_obj_n == 0x32 then --triple crossbow
local index = ((attacker.y - target_y + 5) * 11) + (attacker.x - target_x + 5) + 1
- local triple_crossbow_targets = {
- {x=target_x,
- y=target_y,
- z=target_z},
- {x=target_x + movement_offset_x_tbl[g_projectile_offset_tbl[1][index]+1],
- y=target_y + movement_offset_y_tbl[g_projectile_offset_tbl[1][index]+1],
- z=target_z},
- {x=target_x + movement_offset_x_tbl[g_projectile_offset_tbl[2][index]+1],
- y=target_y + movement_offset_y_tbl[g_projectile_offset_tbl[2][index]+1],
- z=target_z}
- }
-
- projectile_anim_multi(projectile_weapon_tbl[weapon_obj_n][1], attacker.x, attacker.y, triple_crossbow_targets, projectile_weapon_tbl[weapon_obj_n][3], 0, projectile_weapon_tbl[weapon_obj_n][2])
+ targets = {
+ {x=target_x,
+ y=target_y,
+ z=target_z},
+ {x=target_x + movement_offset_x_tbl[g_projectile_offset_tbl[1][index]+1],
+ y=target_y + movement_offset_y_tbl[g_projectile_offset_tbl[1][index]+1],
+ z=target_z},
+ {x=target_x + movement_offset_x_tbl[g_projectile_offset_tbl[2][index]+1],
+ y=target_y + movement_offset_y_tbl[g_projectile_offset_tbl[2][index]+1],
+ z=target_z}
+ }
+ else --not triple crossbow
+ targets = {
+ {x=target_x,
+ y=target_y,
+ z=target_z}
+ }
+ end
+
+ -- Collision checking
+ -- Sets up two tables:
+ -- coll_tiles: New target tile and foe for each projectile after collision check
+ -- pre_coll_tiles: Tile traversed before each collision (used for animation and thrown weapon placement)
+ for i=1,num_bolts do
+ targ = targets[i]
+ local coll_x, coll_y, pre_coll_x, pre_coll_y = map_line_hit_check(attacker.x, attacker.y, targ.x, targ.y, targ.z)
+ foe = map_get_actor(coll_x, coll_y, targ.z)
+ if foe == nil then foe = map_get_obj(coll_x, coll_y , targ.z) end
+ table.insert(coll_tiles, {x = coll_x, y = coll_y, z = targ.z, foe = foe})
+ table.insert(pre_coll_tiles, {x = pre_coll_x, y = pre_coll_y, z = targ.z})
+ end
+
+ -- Projectile animation
+ -- TODO: Animation currently does its own collision checking. This should only be done once.
+ if weapon_obj_n == 0x32 then --triple crossbow
+ projectile_anim_multi(projectile_weapon_tbl[weapon_obj_n][1], attacker.x, attacker.y, targets, projectile_weapon_tbl[weapon_obj_n][3], 0, projectile_weapon_tbl[weapon_obj_n][2])
else
projectile(projectile_weapon_tbl[weapon_obj_n][1], attacker.x, attacker.y, target_x, target_y, projectile_weapon_tbl[weapon_obj_n][3], projectile_weapon_tbl[weapon_obj_n][4])
end
@@ -1654,7 +1664,7 @@ function combat_range_weapon_1D5F9(attacker, target_x, target_y, target_z, foe,
Actor.inv_remove_obj_qty(attacker, projectile_obj, qty)
end
- return 1
+ return coll_tiles --original always returns 1
end
--
Commit: 12da032467f551dcaaee115ffc5accd4fdf87f91
https://github.com/scummvm/scummvm/commit/12da032467f551dcaaee115ffc5accd4fdf87f91
Author: PushmePullyu (127053144+PushmePullyu at users.noreply.github.com)
Date: 2023-12-18T17:41:33+11:00
Commit Message:
ULTIMA: ULTIMA6: Fix triple crossbow extra projectile targeting
Changed paths:
devtools/create_ultima/files/ultima6/scripts/u6/actor.lua
diff --git a/devtools/create_ultima/files/ultima6/scripts/u6/actor.lua b/devtools/create_ultima/files/ultima6/scripts/u6/actor.lua
index e63751eaa2b..6d566ae5949 100644
--- a/devtools/create_ultima/files/ultima6/scripts/u6/actor.lua
+++ b/devtools/create_ultima/files/ultima6/scripts/u6/actor.lua
@@ -1561,7 +1561,7 @@ function combat_range_weapon_1D5F9(attacker, target_x, target_y, target_z, weapo
--set up targets table
if weapon_obj_n == 0x32 then --triple crossbow
- local index = ((attacker.y - target_y + 5) * 11) + (attacker.x - target_x + 5) + 1
+ local index = ((target_y - attacker.y + 5) * 11) + (target_x - attacker.x + 5) + 1
targets = {
{x=target_x,
y=target_y,
Commit: 0c5f74b1b4a91cbaed873aba2d52f2e6971eb21c
https://github.com/scummvm/scummvm/commit/0c5f74b1b4a91cbaed873aba2d52f2e6971eb21c
Author: PushmePullyu (127053144+PushmePullyu at users.noreply.github.com)
Date: 2023-12-18T17:41:33+11:00
Commit Message:
ULTIMA: ULTIMA6: Fix boomerang origin coordinates when returning
Changed paths:
devtools/create_ultima/files/ultima6/scripts/u6/actor.lua
diff --git a/devtools/create_ultima/files/ultima6/scripts/u6/actor.lua b/devtools/create_ultima/files/ultima6/scripts/u6/actor.lua
index 6d566ae5949..ab244b2e823 100644
--- a/devtools/create_ultima/files/ultima6/scripts/u6/actor.lua
+++ b/devtools/create_ultima/files/ultima6/scripts/u6/actor.lua
@@ -1536,7 +1536,7 @@ function actor_attack(attacker, target_x, target_y, target_z, weapon, foe)
if weapon_obj_n == 0x31 then --boomerang
if attacker.x ~= 0 and attacker.y ~= 0 then --hack to stop return projectile if the avatar has died
- projectile(projectile_weapon_tbl[weapon_obj_n][1], target_x, target_y, attacker.x, attacker.y, projectile_weapon_tbl[weapon_obj_n][3], projectile_weapon_tbl[weapon_obj_n][4])
+ projectile(projectile_weapon_tbl[weapon_obj_n][1], coll_tiles[1].x, coll_tiles[1].y, attacker.x, attacker.y, projectile_weapon_tbl[weapon_obj_n][3], projectile_weapon_tbl[weapon_obj_n][4])
end
end
end
Commit: de64a96598f9fb7fceb184661f9d3015c1ba2a99
https://github.com/scummvm/scummvm/commit/de64a96598f9fb7fceb184661f9d3015c1ba2a99
Author: PushmePullyu (127053144+PushmePullyu at users.noreply.github.com)
Date: 2023-12-18T17:41:33+11:00
Commit Message:
ULTIMA: ULTIMA6: Fix projectile animation destination coordinates
Changed paths:
devtools/create_ultima/files/ultima6/scripts/u6/actor.lua
diff --git a/devtools/create_ultima/files/ultima6/scripts/u6/actor.lua b/devtools/create_ultima/files/ultima6/scripts/u6/actor.lua
index ab244b2e823..b0ec0bcc9c0 100644
--- a/devtools/create_ultima/files/ultima6/scripts/u6/actor.lua
+++ b/devtools/create_ultima/files/ultima6/scripts/u6/actor.lua
@@ -1597,9 +1597,9 @@ function combat_range_weapon_1D5F9(attacker, target_x, target_y, target_z, weapo
-- Projectile animation
-- TODO: Animation currently does its own collision checking. This should only be done once.
if weapon_obj_n == 0x32 then --triple crossbow
- projectile_anim_multi(projectile_weapon_tbl[weapon_obj_n][1], attacker.x, attacker.y, targets, projectile_weapon_tbl[weapon_obj_n][3], 0, projectile_weapon_tbl[weapon_obj_n][2])
+ projectile_anim_multi(projectile_weapon_tbl[weapon_obj_n][1], attacker.x, attacker.y, coll_tiles, projectile_weapon_tbl[weapon_obj_n][3], 0, projectile_weapon_tbl[weapon_obj_n][2])
else
- projectile(projectile_weapon_tbl[weapon_obj_n][1], attacker.x, attacker.y, target_x, target_y, projectile_weapon_tbl[weapon_obj_n][3], projectile_weapon_tbl[weapon_obj_n][4])
+ projectile(projectile_weapon_tbl[weapon_obj_n][1], attacker.x, attacker.y, coll_tiles[1].x, coll_tiles[1].y, projectile_weapon_tbl[weapon_obj_n][3], projectile_weapon_tbl[weapon_obj_n][4])
end
if weapon_obj_n == 0x5b then
Commit: 1b26c60841452baee1e9495275f5d3852f5e99fc
https://github.com/scummvm/scummvm/commit/1b26c60841452baee1e9495275f5d3852f5e99fc
Author: PushmePullyu (127053144+PushmePullyu at users.noreply.github.com)
Date: 2023-12-18T17:41:33+11:00
Commit Message:
ULTIMA: ULTIMA6: Fix placement of thrown weapons on map
Changed paths:
devtools/create_ultima/files/ultima6/scripts/u6/actor.lua
diff --git a/devtools/create_ultima/files/ultima6/scripts/u6/actor.lua b/devtools/create_ultima/files/ultima6/scripts/u6/actor.lua
index b0ec0bcc9c0..2e6c8aee5ba 100644
--- a/devtools/create_ultima/files/ultima6/scripts/u6/actor.lua
+++ b/devtools/create_ultima/files/ultima6/scripts/u6/actor.lua
@@ -1622,30 +1622,35 @@ function combat_range_weapon_1D5F9(attacker, target_x, target_y, target_z, weapo
if map_is_water(target_x,target_y,target_z) == false then
local obj = Obj.new(317); --fire field
obj.temporary = true
- Obj.moveToMap(obj, target_x, target_y, target_z)
+ Obj.moveToMap(obj, pre_coll_tiles[1].x, pre_coll_tiles[1].y, pre_coll_tiles[1].z)
end
elseif weapon_obj_n == 0x24 or weapon_obj_n == 0x25 or weapon_obj_n == 0x26 then
--spear, throwing axe, dagger
- --remove unreadied throwing weapons from inventory first so weapon stays readied
- local removal_candidate = nil
- for inv_obj in actor_inventory(attacker) do
- if inv_obj.obj_n == weapon_obj_n then
- removal_candidate = inv_obj
- if removal_candidate.readied ~= true then
+ -- Only remove thrown weapon from attacker if distance to target is > 1,
+ -- else just skip handling and keep the item
+ if abs(coll_tiles[1].x - attacker.x) > 1 or abs(coll_tiles[1].y - attacker.y) > 1 then
+ --remove unreadied throwing weapons from inventory first so weapon stays readied
+ local removal_candidate = nil
+ for inv_obj in actor_inventory(attacker) do
+ if inv_obj.obj_n == weapon_obj_n then
+ removal_candidate = inv_obj
+ if removal_candidate.readied ~= true then
break
- end
- end
- end
- if removal_candidate ~= nil then
- Actor.inv_remove_obj(attacker, removal_candidate)
- if map_is_water(target_x,target_y,target_z) == false then
- local obj = Obj.new(weapon_obj_n);
- obj.ok_to_take = true
- obj.temporary = true
- Obj.moveToMap(obj, target_x, target_y, target_z)
- end
+ end
+ end
+ end
+ if removal_candidate ~= nil then
+ Actor.inv_remove_obj(attacker, removal_candidate)
+ -- Do not place thrown weapon if target is an actor
+ if (coll_tiles[1].foe == mil or coll_tiles[1].foe.luatype ~= "actor") and map_is_water(pre_coll_tiles[1].x, pre_coll_tiles[1].y, pre_coll_tiles[1].z) == false then
+ local obj = Obj.new(weapon_obj_n);
+ obj.ok_to_take = true
+ obj.temporary = true
+ Obj.moveToMap(obj, pre_coll_tiles[1].x, pre_coll_tiles[1].y, pre_coll_tiles[1].z)
+ end
+ end
end
elseif weapon_obj_n == 0x29 or weapon_obj_n == 0x2a or weapon_obj_n == 0x32 or weapon_obj_n == 0x36 then
--bow, crossbow, triple crossbow, magic bow
More information about the Scummvm-git-logs
mailing list