mirror of
https://github.com/scummvm/scummvm.git
synced 2026-06-20 05:45:29 +00:00
3722 lines
106 KiB
Lua
3722 lines
106 KiB
Lua
--io.stderr:write("actor.lua get here\n")
|
|
|
|
|
|
--Worktypes
|
|
WT_NOTHING = 0x0 --do nothing
|
|
|
|
WT_FOLLOW = 0x1 --follow avatar (in party)
|
|
|
|
WT_PLAYER = 0x2 --player mode
|
|
|
|
WT_FRONT = 0x3 --combat front
|
|
WT_REAR = 0x4 --combat rear
|
|
WT_FLANK = 0x5 --combat flank
|
|
WT_BERSERK = 0x6 --combat berserk
|
|
WT_RETREAT = 0x7 --combat retreat
|
|
WT_ASSAULT = 0x8 --combat assault
|
|
WT_FLEE = 0x9 --run away from party
|
|
WT_LIKE = 0xa --like the party. eg dog
|
|
WT_UNFRIENDLY = 0xb --wander around but attack if any party member gets too close.
|
|
WT_WANDER_NEAR_PLAYER = 0xc --guards use this.
|
|
WT_TANGLE = 0xd --tangle vine
|
|
WT_STATIONARY = 0xe --stationary attack
|
|
WT_GUARD_WALK_EAST_WEST = 0xf
|
|
WT_GUARD_WALK_NORTH_SOUTH = 0x10
|
|
--11
|
|
WT_GUARD_ARREST_PLAYER = 0x12
|
|
WT_UNK_13 = 0x13 --FIXME I think this is repel undead
|
|
|
|
WT_WALK_TO_LOCATION = 0x86
|
|
WT_FACE_NORTH = 0x87
|
|
WT_FACE_EAST = 0x88
|
|
WT_FACE_SOUTH = 0x89
|
|
WT_FACE_WEST = 0x8a
|
|
WT_WALK_NORTH_SOUTH = 0x8b
|
|
WT_WALK_EAST_WEST = 0x8c
|
|
WT_WALK_SOUTH_NORTH = 0x8d
|
|
WT_WALK_WEST_EAST = 0x8e
|
|
WT_WANDER_AROUND = 0x8f
|
|
WT_WORK = 0x90
|
|
WT_SLEEP = 0x91
|
|
|
|
|
|
WT_UNK_94 = 0x94
|
|
WT_PLAY_LUTE = 0x95
|
|
WT_BEG = 0x96
|
|
|
|
WT_BELL_RINGER = 0x98
|
|
WT_BRAWLING = 0x99
|
|
WT_MOUSE = 0x9a
|
|
WT_ATTACK_PARTY = 0x9b
|
|
|
|
|
|
wt_rear_max_monster = nil
|
|
wt_rear_min_monster = nil
|
|
wt_rear_max_party = nil
|
|
wt_rear_min_party = nil
|
|
|
|
combat_avg_x, combat_avg_y, party_avg_x, party_avg_y = -1, -1, -1, -1
|
|
|
|
wt_front_target_actor = nil
|
|
|
|
wt_num_monsters_near = 0
|
|
|
|
g_time_stopped = false
|
|
|
|
g_update_volcano = false;
|
|
|
|
--Actor stats table
|
|
--[objnum] = {str,dex,int,hp,dmg,alignment,can talk,drops blood,?,?,?,lives in water,flies-immune to tremor,repel undead,poisonous,strength_based,double dmg from fire,immune to magic (fire only),immune to poison,undead and immune to death spells,immune to sleep spell,{spell table},{weapon table},{armor table},{treasure table},exp_related see actor_hit()}
|
|
actor_tbl = {
|
|
--Acid Slug
|
|
[364] = {5, 5, 2, 10, 1, ALIGNMENT_CHAOTIC, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, {}, {}, {}, {}, 0},
|
|
--Alligator
|
|
[429] = {20, 10, 3, 30, 10, ALIGNMENT_CHAOTIC, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, {}, {}, {}, {}, 6},
|
|
--Ant, Giant
|
|
[427] = {16, 15, 2, 10, 8, ALIGNMENT_CHAOTIC, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, {}, {}, {}, {}, 3},
|
|
--Avatar
|
|
[410] = {25, 25, 25, 30, 4, ALIGNMENT_GOOD, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, {}, {}, {}, {}, 0},
|
|
--Bat, Giant
|
|
[344] = {5, 25, 4, 5, 6, ALIGNMENT_CHAOTIC, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, {}, {}, {}, {}, 0},
|
|
--Peasant
|
|
[384] = {8, 8, 9, 6, 3, ALIGNMENT_CHAOTIC, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, {}, {38,34}, {185}, {}, 0},
|
|
--Bird
|
|
[356] = {1, 28, 4, 3, 1, ALIGNMENT_NEUTRAL, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, {}, {}, {}, {}, 0},
|
|
----Child
|
|
[381] = {8, 8, 9, 6, 2, ALIGNMENT_CHAOTIC, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, {}, {}, {}, {}, 0},
|
|
--Corpser
|
|
[357] = {17, 6, 3, 40, 15, ALIGNMENT_CHAOTIC, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, {}, {}, {}, {}, 0},
|
|
--Cow
|
|
[428] = {14, 7, 5, 10, 3, ALIGNMENT_NEUTRAL, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, {}, {}, {}, {129}, 0},
|
|
--Cyclops
|
|
[424] = {27, 8, 7, 40, 20, ALIGNMENT_EVIL, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, {}, {44,33,34}, {20,3,13}, {98}, 4},
|
|
--Daemon
|
|
[367] = {35, 26, 31, 100, 20, ALIGNMENT_EVIL, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, {17,128,34,80}, {}, {}, {}, 10},
|
|
--Deer
|
|
[350] = {11, 18, 5, 8, 2, ALIGNMENT_NEUTRAL, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {}, {}, {}, {129}, 0},
|
|
--Dog
|
|
[349] = {5, 16, 8, 6, 3, ALIGNMENT_NEUTRAL, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {}, {}, {}, {}, 0},
|
|
--Dragon
|
|
[411] = {40, 35, 27, 150, 30, ALIGNMENT_EVIL, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, {34,83,68,96,119}, {}, {}, {98,88,88}, 12},
|
|
--Drake
|
|
[369] = {22, 22, 13, 50, 10, ALIGNMENT_EVIL, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, {34,68}, {}, {}, {88,88}, 4},
|
|
--Woman
|
|
[387] = {10, 14, 15, 8, 4, ALIGNMENT_NEUTRAL, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, {}, {38}, {185}, {88}, 0},
|
|
--Farmer
|
|
[385] = {15, 15, 10, 8, 4, ALIGNMENT_NEUTRAL, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, {}, {105,101}, {17}, {88}, 0},
|
|
--Fighter
|
|
[376] = {20, 17, 11, 20, 6, ALIGNMENT_CHAOTIC, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, {}, {43,42}, {21,10,3,22}, {88,88}, 0},
|
|
--Gargoyle, Winged
|
|
[362] = {15, 32, 33, 50, 6, ALIGNMENT_EVIL, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, {68,65,69}, {46,41,47,49}, {18,1}, {58}, 5},
|
|
--Gargoyle, Worker
|
|
[363] = {25, 19, 8, 30, 15, ALIGNMENT_EVIL, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, {}, {34,49,37}, {1,9,18,20}, {}, 10},
|
|
--Gazer
|
|
[355] = {2, 10, 21, 20, 1, ALIGNMENT_EVIL, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, {20,68,80}, {}, {}, {}, 0},
|
|
--Ghost
|
|
[352] = {1, 10, 9, 20, 12, ALIGNMENT_EVIL, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, {128,99}, {}, {}, {}, 0},
|
|
--Gremlin
|
|
[353] = {2, 26, 7, 5, 1, ALIGNMENT_CHAOTIC, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {}, {}, {}, {}, 0},
|
|
--Guard
|
|
[382] = {9, 30, 9, 100, 8, ALIGNMENT_EVIL, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, {}, {42,47}, {22,10,3}, {88}, 0},
|
|
--Headless
|
|
[370] = {19, 13, 8, 20, 12, ALIGNMENT_EVIL, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, {}, {34,36}, {17,9}, {88}, 2},
|
|
--Horse
|
|
[430] = {22, 27, 7, 15, 3, ALIGNMENT_NEUTRAL, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, {}, {}, {}, {}, 0},
|
|
--Horse with rider
|
|
[431] = {22, 27, 7, 15, 3, ALIGNMENT_NEUTRAL, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, {}, {}, {}, {}, 0},
|
|
--Hydrae
|
|
[374] = {26, 11, 2, 50, 15, ALIGNMENT_CHAOTIC, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, {69,96,98,68}, {}, {}, {}, 0},
|
|
--Insects
|
|
[343] = {1, 40, 1, 1, 1, ALIGNMENT_CHAOTIC, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, {}, {}, {}, {}, 0},
|
|
--Jester
|
|
[383] = {14, 16, 12, 8, 4, ALIGNMENT_CHAOTIC, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, {}, {38,33}, {17}, {88}, 0},
|
|
--Lord British
|
|
[409] = {30, 30, 30, 255, 255, ALIGNMENT_GOOD, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, {}, {}, {}, {}, 30},
|
|
--Musician
|
|
[386] = {12, 16, 14, 8, 4, ALIGNMENT_CHAOTIC, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, {}, {41,33,43}, {19,1,9}, {88,158}, 0},
|
|
--Mage
|
|
[378] = {10, 14, 22, 30, 4, ALIGNMENT_EVIL, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, {17,34,20,49,68,80,69,83}, {38}, {17,1}, {58,98,88}, 0},
|
|
--Merchant
|
|
[380] = {12, 12, 18, 8, 4, ALIGNMENT_EVIL, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, {}, {38,43}, {17,1}, {88}, 0},
|
|
--Mimic
|
|
[98] = {22, 9, 8, 30, 15, ALIGNMENT_CHAOTIC, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, {18,80}, {}, {}, {98,98}, 5},
|
|
--Mongbat
|
|
[372] = {20, 27, 13, 30, 20, ALIGNMENT_EVIL, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, {}, {38,43,36,37}, {9,17,18}, {98,88}, 4},
|
|
--Mouse
|
|
[354] = {2, 25, 3, 5, 2, ALIGNMENT_NEUTRAL, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {}, {}, {}, {}, 0},
|
|
--Rabbit
|
|
[359] = {3, 9, 3, 5, 2, ALIGNMENT_NEUTRAL, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {}, {}, {}, {}, 0},
|
|
--Rat, Giant
|
|
[342] = {5, 13, 4, 8, 6, ALIGNMENT_CHAOTIC, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, {}, {}, {}, {}, 0},
|
|
--Reaper
|
|
[347] = {21, 20, 16, 30, 20, ALIGNMENT_CHAOTIC, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, {17,80,66,68}, {}, {}, {58,88}, 4},
|
|
--Rot Worm
|
|
[360] = {3, 17, 2, 5, 2, ALIGNMENT_CHAOTIC, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, {}, {}, {}, {}, 0},
|
|
--Scorpion, Giant
|
|
[426] = {13, 13, 3, 20, 8, ALIGNMENT_CHAOTIC, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, {}, {}, {}, {}, 3},
|
|
--Sea Serpent
|
|
[346] = {17, 17, 9, 70, 30, ALIGNMENT_EVIL, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, {34,83,51}, {}, {}, {}, 2},
|
|
--Sheep
|
|
[348] = {5, 10, 4, 6, 2, ALIGNMENT_NEUTRAL, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {}, {}, {}, {129}, 0},
|
|
--Ship
|
|
[412] = {30, 30, 30, 30, 30, ALIGNMENT_CHAOTIC, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, {}, {}, {}, {}, 30},
|
|
--Silver Serpent
|
|
[413] = {60, 21, 8, 200, 60, ALIGNMENT_CHAOTIC, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, {}, {}, {}, {}, 15},
|
|
--Skeleton
|
|
[368] = {10, 14, 7, 20, 6, ALIGNMENT_EVIL, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, {}, {43,36,37,41,38}, {9,1}, {88}, 0},
|
|
--Slime
|
|
[375] = {6, 6, 2, 15, 4, ALIGNMENT_CHAOTIC, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, {}, {}, {}, {}, 0},
|
|
--Snake
|
|
[358] = {3, 7, 6, 5, 2, ALIGNMENT_CHAOTIC, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, {}, {}, {}, {}, 1},
|
|
--Spider, Giant
|
|
[361] = {9, 11, 4, 10, 8, ALIGNMENT_CHAOTIC, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, {89}, {}, {}, {129}, 0},
|
|
--Squid, Giant
|
|
[345] = {24, 20, 8, 50, 20, ALIGNMENT_EVIL, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, {17,68}, {}, {}, {}, 0},
|
|
--Swashbuckler
|
|
[377] = {15, 18, 12, 15, 4, ALIGNMENT_CHAOTIC, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, {}, {43,41,33}, {19,1,9}, {88,88}, 0},
|
|
--Tangle Vine
|
|
[366] = {20, 25, 1, 30, 1, ALIGNMENT_CHAOTIC, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, {}, {}, {}, {}, 4},
|
|
--Troll
|
|
[371] = {18, 14, 9, 15, 6, ALIGNMENT_EVIL, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, {}, {37,36,43,41,34}, {9,18,1,19}, {98,88,88}, 4},
|
|
--Villager
|
|
[379] = {11, 12, 12, 8, 4, ALIGNMENT_CHAOTIC, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, {}, {43,33}, {17}, {88}, 0},
|
|
--Wisp
|
|
[373] = {1, 40, 20, 40, 1, ALIGNMENT_CHAOTIC, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, {20,69,129}, {}, {}, {}, 0},
|
|
--Wolf
|
|
[351] = {8, 16, 8, 8, 4, ALIGNMENT_CHAOTIC, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {}, {}, {}, {}, 0},
|
|
--TV Flower
|
|
[365] = {20, 5, 1, 30, 1, ALIGNMENT_CHAOTIC, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, {20}, {}, {}, {}, 4},
|
|
--Skiff
|
|
[414] = {20, 20, 20, 20, 20, ALIGNMENT_CHAOTIC, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, {}, {}, {}, {}, 20},
|
|
--Raft
|
|
[415] = {10, 10, 10, 10, 10, ALIGNMENT_CHAOTIC, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, {}, {}, {}, {}, 10},
|
|
--Balloon
|
|
[423] = {10, 10, 10, 10, 10, ALIGNMENT_CHAOTIC, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, {}, {}, {}, {}, 10},
|
|
--Cat
|
|
[388] = {4, 18, 8, 6, 2, ALIGNMENT_NEUTRAL, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {}, {}, {}, {}, 0},
|
|
--Sinjen (Yew Stocks guy)
|
|
[263] = {11, 12, 12, 8, 4, ALIGNMENT_CHAOTIC, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {}, {}, {}, {}, 0}
|
|
}
|
|
|
|
monster_inv_food = { 129, 133, 128 } --portion of meat, ham, loaf of bread
|
|
|
|
function actor_put_to_sleep(actor)
|
|
if actor.obj_n == 431 then --horse with rider
|
|
Actor.use(actor) --dismount from horse
|
|
end
|
|
|
|
if actor.actor_num ~= 0 then
|
|
actor.asleep = true
|
|
if actor.in_party == true then
|
|
party_update_leader()
|
|
end
|
|
end
|
|
end
|
|
|
|
function actor_can_turn_invisible(obj_n)
|
|
|
|
if obj_n < 0x1aa and obj_n ~= 0x19b and obj_n ~= 0x176 and obj_n ~= 0x19d and obj_n ~= 0x177 then --giant scorpion, dragon, hydra, silver serpent, slime
|
|
return true
|
|
end
|
|
|
|
return false
|
|
end
|
|
|
|
-- returns true if defender loses the check
|
|
function actor_int_check(defender, attacker)
|
|
|
|
if is_god_mode_enabled() then
|
|
if defender.in_party then
|
|
return true
|
|
end
|
|
if attacker.in_party then
|
|
return false
|
|
end
|
|
end
|
|
if (math.floor(actor_int_adj(attacker) / 2) + 15) - actor_int_adj(defender) > math.random(1, 30) then
|
|
return true -- defender lost
|
|
end
|
|
|
|
return false
|
|
-- if((actor1_int_adj / 2 + 15) - actor2_int_adj > random(1,30))
|
|
--return
|
|
|
|
end
|
|
|
|
function subtract_movement_pts(actor, pts)
|
|
if actor.obj_n == 0x1af then pts = math.floor(pts / 2) end --if horse with rider
|
|
|
|
--fixme check with the original there are two timers that are checked but never seem to be used.
|
|
|
|
if pts < 1 then pts = 1 end
|
|
|
|
actor.mpts = actor.mpts - pts
|
|
|
|
if g_avatar_died == true then
|
|
actor_avatar_death()
|
|
end
|
|
end
|
|
|
|
function actor_move(actor, direction, flag)
|
|
----dgb("actor_move("..actor.name..", "..direction_string(direction)..", "..flag..") actor("..actor.x..","..actor.y..")\n");
|
|
local x,y,z = actor.x, actor.y, actor.z
|
|
if direction == DIR_NORTH then y = y - 1 end
|
|
if direction == DIR_SOUTH then y = y + 1 end
|
|
if direction == DIR_EAST then x = x + 1 end
|
|
if direction == DIR_WEST then x = x - 1 end
|
|
|
|
actor.direction = direction
|
|
local did_move = Actor.move(actor, x, y, z)
|
|
|
|
--actor.direction = direction
|
|
|
|
if did_move then
|
|
if actor.obj_n == 0x177 then slime_update_frames() end
|
|
subtract_map_movement_pts(actor)
|
|
----dgb("actor_move() did move actor("..actor.x..","..actor.y..")\n");
|
|
end
|
|
|
|
return did_move and 1 or 0
|
|
end
|
|
|
|
function actor_move_diagonal(actor, x_direction, y_direction)
|
|
local x,y,z = actor.x, actor.y, actor.z
|
|
local direction
|
|
|
|
if y_direction == DIR_NORTH then
|
|
y = y - 1
|
|
direction = x_direction == DIR_EAST and DIR_NORTHEAST or DIR_NORTHWEST
|
|
end
|
|
if y_direction == DIR_SOUTH then
|
|
y = y + 1
|
|
direction = x_direction == DIR_EAST and DIR_SOUTHEAST or DIR_SOUTHWEST
|
|
end
|
|
if x_direction == DIR_EAST then
|
|
x = x + 1
|
|
direction = y_direction == DIR_NORTH and DIR_NORTHEAST or DIR_SOUTHEAST
|
|
end
|
|
if x_direction == DIR_WEST then
|
|
x = x - 1
|
|
direction = y_direction == DIR_NORTH and DIR_NORTHWEST or DIR_SOUTHWEST
|
|
end
|
|
|
|
----dgb("actor_move_diagonal("..actor.name..", "..direction_string(direction)..")\n");
|
|
actor.direction = y_direction
|
|
local did_move = Actor.move(actor, x, y, z)
|
|
|
|
if did_move then
|
|
----dgb("did move\n");
|
|
if actor.obj_n == 0x177 then slime_update_frames() end
|
|
subtract_map_movement_pts(actor)
|
|
|
|
--dgb("set dir = "..direction_string(direction).." y_dir ="..direction_string(y_direction).." ")
|
|
end
|
|
|
|
return did_move and 1 or 0
|
|
end
|
|
|
|
function actor_map_dmg(actor, map_x, map_y, map_z)
|
|
local obj_n = actor.obj_n
|
|
local actor_type = actor_tbl[obj_n]
|
|
|
|
if actor.alive == false or actor.hit_flag == true then
|
|
return
|
|
end
|
|
|
|
if obj_n ~= 0x1a7 and obj_n ~= 0x19e and obj_n ~= 0x19f and obj_n ~= 0x19c --balloon, skiff, raft, ship, immune to map dmg
|
|
and (actor_type == nil or actor_type[13] == 0) and actor.protected == false and actor.in_vehicle == false then
|
|
local map_tile = map_get_dmg_tile_num(map_x, map_y, map_z)
|
|
if map_tile ~= nil then
|
|
actor_tile_dmg(actor, map_tile)
|
|
|
|
if map_tile == 732 then
|
|
local trap_obj = map_get_obj(map_x, map_y, map_z, 0xad) --trap
|
|
if trap_obj ~= nil then
|
|
trap_obj.invisible = false
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function actor_tile_dmg(actor, map_tile)
|
|
if is_god_mode_enabled() and actor.in_party then
|
|
return
|
|
end
|
|
local obj_n = actor.obj_n
|
|
local actor_type = actor_tbl[actor.obj_n]
|
|
local dmg = 0
|
|
local random = math.random
|
|
if map_tile ~= nil then
|
|
actor.hit_flag = true
|
|
if map_tile == 564 then
|
|
--web
|
|
if obj_n ~= 0x169 then --giant spider
|
|
local str = actor_str_adj(actor)
|
|
if str < random(1, 0x1e) then
|
|
actor.paralyzed = true
|
|
print("`"..actor.name.." is stuck in a web!\n")
|
|
end
|
|
end
|
|
elseif (map_tile >= 2 and map_tile <= 5) or map_tile == 1165 then --swamp tiles or poison field.
|
|
--poison
|
|
local swamp_boots = Actor.inv_get_readied_obj_n(actor, 7) == 0x1c --swamp boots
|
|
if swamp_boots == false or map_tile == 1165 then
|
|
if (actor_type == nil or actor_type[19] == 0) and actor.poisoned == false then --19 immune to poison
|
|
actor.poisoned = true
|
|
print(actor.name.." poisoned!\n")
|
|
hit_anim(actor.x, actor.y)
|
|
end
|
|
end
|
|
elseif (map_tile >= 220 and map_tile <= 223) or map_tile == 890 or map_tile == 1124 or map_tile == 1125 or map_tile == 1130 or map_tile == 1131 or map_tile == 1164 or map_tile == 1193 then
|
|
--fire
|
|
if map_tile == 1164 then
|
|
dmg = random(1, 0x1e)
|
|
else
|
|
dmg = random(1, 8)
|
|
end
|
|
if actor_type ~= nil and actor_type[17] == 1 then --double damage from fire
|
|
dmg = dmg * 2
|
|
end
|
|
|
|
actor_hit(actor, dmg, nil)
|
|
|
|
elseif map_tile == 732 or map_tile == 1010 then
|
|
--trap, log saw
|
|
|
|
actor_hit(actor, random(1, 0x1e), nil)
|
|
|
|
elseif (map_tile >= 1458 and map_tile <= 1463) then
|
|
if obj_n ~= 0x16e then --tangle vine
|
|
actor_hit(actor, random(1, 8), nil)
|
|
end
|
|
elseif map_tile == 562 or map_tile == 731 then
|
|
--force field, spikes
|
|
actor_hit(actor, random(1, 8), nil)
|
|
|
|
elseif map_tile == 1167 then
|
|
--sleepfield
|
|
if (actor_type == nil or actor_type[21] == 0) and actor.asleep == false then --21 immune to sleep spell
|
|
actor_put_to_sleep(actor)
|
|
end
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
function actor_get_max_magic_points(actor)
|
|
local obj_n = actor.base_obj_n
|
|
if obj_n == 410 then --avatar
|
|
return actor.int * 2
|
|
end
|
|
|
|
if obj_n == 378 then --mage
|
|
return actor.int
|
|
end
|
|
|
|
if obj_n == 377 or obj_n == 386 then --swashbuckler, musician
|
|
return math.floor(actor.int/2)
|
|
end
|
|
|
|
return 0
|
|
end
|
|
|
|
function actor_str_adj(actor)
|
|
|
|
local str = actor.str
|
|
|
|
if actor.cursed == false then return str end
|
|
|
|
if str <= 3 then
|
|
return 1
|
|
end
|
|
|
|
return str - 3
|
|
end
|
|
|
|
function actor_dex_adj(actor)
|
|
|
|
local dex = actor.dex
|
|
if actor.cursed == true then
|
|
if dex <= 3 then
|
|
dex = 1
|
|
else
|
|
dex = dex - 3
|
|
end
|
|
end
|
|
|
|
if g_time_stopped == true or actor.asleep == true then
|
|
dex = 1
|
|
end
|
|
|
|
return dex
|
|
end
|
|
|
|
function actor_int_adj(actor)
|
|
local int = actor.int
|
|
|
|
if actor.cursed == true then
|
|
int = int - 3
|
|
end
|
|
|
|
if int < 1 then int = 1 end
|
|
|
|
return int
|
|
end
|
|
|
|
--
|
|
-- actor_combat_hit_check(attacker, foe, weapon_obj)
|
|
--
|
|
|
|
function actor_combat_hit_check(attacker, foe, weapon_obj)
|
|
|
|
if foe == nil then return false end
|
|
if is_god_mode_enabled() and attacker.in_party then
|
|
return true
|
|
end
|
|
if foe.luatype ~= "actor" or weapon_obj.obj_n == 48 then --48 glass sword
|
|
--dgb(foe.luatype)
|
|
return true
|
|
end
|
|
|
|
local use_str = false
|
|
local obj_n = weapon_obj.obj_n
|
|
|
|
if weapon_obj == attacker then
|
|
if actor_tbl[obj_n][16] == 1 then --actor uses strength
|
|
use_str = true
|
|
end
|
|
else
|
|
if obj_n == 4 or obj_n == 34 or obj_n == 39 or obj_n == 44 then --spiked helm, club, mace, two-handed hammer
|
|
use_str = true
|
|
end
|
|
end
|
|
|
|
local attack_role
|
|
|
|
if use_str then
|
|
attack_role = actor_str_adj(attacker)
|
|
else
|
|
attack_role = actor_dex_adj(attacker)
|
|
end
|
|
|
|
local foe_dex = actor_dex_adj(foe)
|
|
local roll = math.random(1,30)
|
|
|
|
--dgb("foe_dex = "..foe_dex.." attack_role = "..attack_role.." random(1,30) = "..roll.."\n\n")
|
|
|
|
if math.floor((foe_dex + 30 - attack_role) / 2) >= roll then
|
|
return false
|
|
end
|
|
|
|
return true
|
|
end
|
|
|
|
--
|
|
-- actor_init(actor)
|
|
--
|
|
|
|
function actor_init(actor, alignment)
|
|
|
|
local actor_base = actor_tbl[actor.obj_n]
|
|
if actor_base ~= nil then
|
|
|
|
actor.str = actor_randomise_stat(actor_base[1])
|
|
actor.dex = actor_randomise_stat(actor_base[2])
|
|
actor.int = actor_randomise_stat(actor_base[3])
|
|
local hp = actor_randomise_stat(actor_base[4])
|
|
actor.hp = hp
|
|
actor.level = math.floor((hp + 29) / 30)
|
|
actor.align = actor_base[6]
|
|
else
|
|
actor.str = 10
|
|
actor.dex = 10
|
|
actor.int = 10
|
|
actor.hp = 30
|
|
actor.level = 1
|
|
--actor.status = 32
|
|
end
|
|
|
|
if alignment ~= nil and alignment ~= ALIGNMENT_DEFAULT then
|
|
actor.align = alignment
|
|
end
|
|
|
|
actor.wt = 8
|
|
actor.combat_mode = 8
|
|
actor.magic = actor_get_max_magic_points(actor)
|
|
actor.mpts = actor.dex
|
|
actor.exp = 100
|
|
|
|
if actor.obj_n == 0x16d then --tangle vine pod. Add tangle vines.
|
|
local actor_x = actor.x
|
|
local actor_y = actor.y
|
|
local actor_z = actor.z
|
|
local a
|
|
|
|
if map_can_put(actor_x + 1, actor_y, actor_z) then
|
|
a = Actor.new(0x16e, actor_x + 1, actor_y, actor_z, actor.align, WT_TANGLE)
|
|
if a ~= nil then a.direction = DIR_EAST end
|
|
end
|
|
if map_can_put(actor_x - 1, actor_y, actor_z) then
|
|
a = Actor.new(0x16e, actor_x - 1, actor_y, actor_z, actor.align, WT_TANGLE)
|
|
if a ~= nil then a.direction = DIR_WEST end
|
|
end
|
|
if map_can_put(actor_x, actor_y + 1, actor_z) then
|
|
a = Actor.new(0x16e, actor_x, actor_y + 1, actor_z, actor.align, WT_TANGLE)
|
|
if a ~= nil then a.direction = DIR_SOUTH end
|
|
end
|
|
if map_can_put(actor_x, actor_y - 1, actor_z) then
|
|
a = Actor.new(0x16e, actor_x, actor_y - 1, actor_z, actor.align, WT_TANGLE)
|
|
if a ~= nil then a.direction = DIR_NORTH end
|
|
end
|
|
end
|
|
|
|
if actor_base ~= nil then
|
|
|
|
local obj,i,v,j,qty,chance,chest
|
|
|
|
--add spells
|
|
for i,v in ipairs(actor_base[22]) do
|
|
obj = Obj.new(336) --charge
|
|
obj.quality = v
|
|
obj.qty = 1
|
|
obj.status = 56
|
|
Actor.inv_add_obj(actor, obj)
|
|
end
|
|
|
|
--actor weapon
|
|
chance = 2
|
|
for i,v in ipairs(actor_base[23]) do
|
|
if v >= 36 and v <= 38 then --spear, throwing axe, dagger
|
|
qty = math.random(6, 12)
|
|
else
|
|
qty = 1
|
|
end
|
|
|
|
for j=1,qty do
|
|
obj = Obj.new(v)
|
|
obj.status = 57
|
|
if v == 90 then
|
|
obj.qty = 1
|
|
else
|
|
obj.qty = 0
|
|
end
|
|
Actor.inv_add_obj(actor, obj)
|
|
Actor.inv_ready_obj(actor, obj)
|
|
if v == 41 or v == 54 then --bow, magic bow
|
|
obj = Obj.new(55) --arrow
|
|
obj.status = 49
|
|
obj.qty = math.random(12, 24)
|
|
Actor.inv_add_obj(actor, obj)
|
|
elseif v == 42 or v == 50 then --crossbow, triple crossbow
|
|
obj = Obj.new(56) --bolt
|
|
obj.status = 49
|
|
obj.qty = math.random(12, 24)
|
|
Actor.inv_add_obj(actor, obj)
|
|
end
|
|
end
|
|
|
|
chance = chance * 2
|
|
end
|
|
|
|
-- actor armor
|
|
chance = 2
|
|
for i,v in ipairs(actor_base[24]) do
|
|
|
|
if math.random(1,chance) == 1 then
|
|
|
|
obj = Obj.new(v)
|
|
obj.status = 57
|
|
obj.qty = 1
|
|
obj.status = 56
|
|
Actor.inv_add_obj(actor, obj)
|
|
Actor.inv_ready_obj(actor, obj)
|
|
end
|
|
|
|
chance = chance * 2
|
|
end
|
|
|
|
--actor treasure
|
|
chance = 2
|
|
for i,v in ipairs(actor_base[25]) do
|
|
|
|
if math.random(1,chance) == 1 then
|
|
if v == 98 then --chest
|
|
chest = Obj.new(v)
|
|
chest.frame_n = 1
|
|
chest.status = 41
|
|
chest.qty = math.random(1, 100)
|
|
Actor.inv_add_obj(actor, chest)
|
|
if math.random(0, 1) == 1 then
|
|
obj = Obj.new(337) --effect
|
|
obj.status = 41
|
|
obj.qty = 1
|
|
obj.quality = 22
|
|
Obj.moveToCont(obj, chest)
|
|
end
|
|
if math.random(0, 3) ~= 0 then
|
|
obj = Obj.new(88) --gold coin
|
|
obj.status = 41
|
|
obj.qty = math.random(1, 100)
|
|
Obj.moveToCont(obj, chest)
|
|
end
|
|
if math.random(0, 3) ~= 0 then
|
|
obj = Obj.new(monster_inv_food[math.random(1, 3)])
|
|
obj.status = 41
|
|
obj.qty = math.random(1, 10)
|
|
Obj.moveToCont(obj, chest)
|
|
end
|
|
if math.random(0, 3) == 0 then
|
|
obj = Obj.new(90) --torch
|
|
obj.status = 41
|
|
obj.qty = math.random(1, 6)
|
|
Obj.moveToCont(obj, chest)
|
|
end
|
|
if math.random(0, 10) == 0 then
|
|
obj = Obj.new(77) --gem
|
|
obj.status = 41
|
|
obj.qty = math.random(1, 4)
|
|
Obj.moveToCont(obj, chest)
|
|
end
|
|
elseif v == 58 then --spell
|
|
if math.random(0, 3) ~= 0 and actor.obj_n ~= 362 then --Gargoyle
|
|
obj = Obj.new(88)
|
|
obj.status = 49
|
|
obj.qty = math.random(1, 100)
|
|
Actor.inv_add_obj(actor, obj)
|
|
end
|
|
if math.random(0, 3) == 0 then
|
|
obj = Obj.new(monster_inv_food[math.random(1, 3)])
|
|
obj.status = 49
|
|
obj.qty = math.random(1, 100)
|
|
Actor.inv_add_obj(actor, obj)
|
|
end
|
|
if math.random(0, 3) == 0 then
|
|
obj = Obj.new(275) --potion
|
|
obj.frame_n = math.random(0, 7) --random potion type
|
|
obj.status = 49
|
|
obj.qty = 1
|
|
Actor.inv_add_obj(actor, obj)
|
|
end
|
|
elseif v == 88 then --gold coin
|
|
obj = Obj.new(v)
|
|
obj.status = 49
|
|
obj.qty = math.random(1,30) + math.random(1, 30)
|
|
Actor.inv_add_obj(actor, obj)
|
|
else
|
|
obj = Obj.new(v)
|
|
obj.quality = 49
|
|
obj.qty = 1
|
|
Actor.inv_add_obj(actor, obj)
|
|
end
|
|
|
|
end
|
|
|
|
chance = chance * 2
|
|
end
|
|
end
|
|
end
|
|
|
|
-- [objectnum] = range
|
|
g_range_weapon_tbl = {
|
|
[40] = 2, -- morning star
|
|
[47] = 2, -- halberd
|
|
[38] = 3, -- dagger
|
|
[83] = 5, -- flask of oil
|
|
[33] = 4, -- sling
|
|
[37] = 3, -- throwing axe
|
|
[36] = 4, -- spear
|
|
[41] = 5, -- bow
|
|
[42] = 7, -- crossbow
|
|
[57] = 7, -- spellbook
|
|
[336] = 5, -- charge
|
|
[49] = 5, -- boomerang
|
|
[50] = 7, -- triple crossbow
|
|
[412] = 5, -- ship
|
|
[91] = 4, -- Zu Ylem
|
|
[54] = 7, -- magic bow
|
|
[79] = 7, -- lightning wand
|
|
[80] = 7, -- fire wand
|
|
}
|
|
|
|
local projectile_weapon_tbl =
|
|
{
|
|
--obj_n = {tile_num, initial_tile_rotation, speed, rotation_amount}
|
|
[33] = {398, 0, 2, 0}, -- sling
|
|
[36] = {547, 45,3, 0}, -- spear
|
|
[37] = {548, 0, 2, 10}, -- throwing axe
|
|
[38] = {549, 0, 2, 10}, -- dagger
|
|
[41] = {566, 90,4, 0}, -- bow
|
|
[42] = {567, 90,4, 0}, -- crossbow
|
|
[49] = {560, 0, 4, 10}, -- boomerang
|
|
[83] = {601, 0, 2, 0}, -- flask of oil
|
|
[50] = {567, 90,4, 0}, -- triple crossbow
|
|
[412] = {399, 0,2, 0}, -- ship
|
|
[91] = {612, 0, 2, 10}, -- Zu Ylem
|
|
[54] = {566, 90,4, 0}, -- magic bow
|
|
[79] = {392, 0, 2, 0}, -- lightning wand
|
|
[80] = {393, 0, 2, 0}, -- fire wand
|
|
}
|
|
|
|
weapon_dmg_tbl = {
|
|
[4] = 4, --spiked helm
|
|
[33] = 6, --sling
|
|
[34] = 8, --club
|
|
[35] = 8, --main gauche
|
|
[36] = 10, --spear
|
|
[37] = 10, --throwing axe
|
|
[38] = 6, --dagger
|
|
[39] = 15, --mace
|
|
[40] = 15, --morning star
|
|
[41] = 10, --bow
|
|
[42] = 12, --crossbow
|
|
[43] = 15, --sword
|
|
[44] = 20, --two-handed hammer
|
|
[45] = 20, --two-handed axe
|
|
[46] = 20, --two-handed sword
|
|
[47] = 30, --halberd
|
|
[49] = 8, --boomerang
|
|
[50] = 12, --triple crossbow
|
|
[48] = 255, --glass sword
|
|
[13] = 4, --spiked shield
|
|
[221] = 90, --cannon
|
|
[83] = 4, --flask of oil
|
|
[54] = 20, --magic bow
|
|
[109] = 2, --rolling pin
|
|
[100] = 6, --scythe
|
|
[101] = 4, --pitchfork
|
|
[103] = 4, --pick
|
|
[104] = 4, --shovel
|
|
[105] = 4, --hoe
|
|
[113] = 4, --cleaver
|
|
[114] = 4, --knife
|
|
[141] = 4, --decorative sword
|
|
[412] = 30, --ship
|
|
[91] = 0, --Zu Ylem
|
|
[78] = 4, --staff
|
|
[79] = 30, --lightning wand
|
|
[80] = 20, --fire wand
|
|
}
|
|
|
|
armour_tbl =
|
|
{
|
|
[1] = 1, --leather helm
|
|
[2] = 2, --chain coif
|
|
[3] = 3, --iron helm
|
|
[4] = 3, --spiked helm
|
|
[5] = 2, --winged helm
|
|
[6] = 2, --brass helm
|
|
[7] = 3, --Gargoyle Helm
|
|
[8] = 5, --magic helm
|
|
[9] = 2, --wooden shield
|
|
[10] = 3, --curved heater
|
|
[11] = 3, --winged shield
|
|
[12] = 3, --kite shield
|
|
[13] = 2, --spiked shield
|
|
[14] = 2, --black shield
|
|
[15] = 4, --door shield
|
|
[16] = 5, --magic shield
|
|
[17] = 1, --cloth armour
|
|
[18] = 2, --leather armor
|
|
[19] = 3, --ring mail
|
|
[20] = 4, --scale mail
|
|
[21] = 5, --chain mail
|
|
[22] = 7, --plate mail
|
|
[23] = 10, --magic armour
|
|
[35] = 1, --main gauche
|
|
[24] = 2, --spiked collar
|
|
[256] = 5, --protection ring
|
|
}
|
|
|
|
function get_weapon_dmg(weapon_obj_n)
|
|
local dmg = weapon_dmg_tbl[weapon_obj_n]
|
|
|
|
if dmg == nil and actor_tbl[weapon_obj_n] ~= nil then
|
|
dmg = actor_tbl[weapon_obj_n][5]
|
|
end
|
|
|
|
return dmg
|
|
end
|
|
|
|
function actor_get_ac(actor)
|
|
|
|
local ac = 0
|
|
local obj
|
|
|
|
for obj in actor_inventory(actor) do
|
|
if obj.readied then
|
|
|
|
local armour = armour_tbl[obj.obj_n]
|
|
if armour ~= nil then
|
|
ac = ac + armour
|
|
end
|
|
end
|
|
end
|
|
|
|
if actor.cursed == true then
|
|
ac = ac - 3
|
|
end
|
|
|
|
if actor.protected == true then
|
|
ac = ac + 3
|
|
end
|
|
|
|
return ac
|
|
end
|
|
|
|
function actor_select_obj_from_tbl(actor, obj_list_tbl)
|
|
local obj
|
|
local selected_obj = nil
|
|
local random = math.random
|
|
for obj in actor_inventory(actor) do
|
|
if obj_list_tbl[obj.obj_n] ~= nil then
|
|
if selected_obj == nil or random(0, 1) == 0 then
|
|
selected_obj = obj
|
|
end
|
|
end
|
|
end
|
|
|
|
return selected_obj
|
|
end
|
|
|
|
function acid_slug_dissolve_item(target_actor)
|
|
local acid_slug_items = { [0x2] = 1,
|
|
[0x3] = 1,
|
|
[0x4] = 1,
|
|
[0x5] = 1,
|
|
[0x7] = 1,
|
|
[0x0A] = 1,
|
|
[0x0B] = 1,
|
|
[0x0C] = 1,
|
|
[0x0D] = 1,
|
|
[0x0F] = 1,
|
|
[0x13] = 1,
|
|
[0x14] = 1,
|
|
[0x15] = 1,
|
|
[0x16] = 1,
|
|
[0x23] = 1,
|
|
[0x26] = 1,
|
|
[0x2B] = 1,
|
|
[0x71] = 1,
|
|
[0x72] = 1 }
|
|
|
|
local obj = actor_select_obj_from_tbl(target_actor, acid_slug_items)
|
|
|
|
if obj ~= nil then
|
|
play_sfx(SFX_SLUG_DISSOLVE, true)
|
|
print("A slug dissolves "..target_actor.name.."'s "..obj.name.."!\n")
|
|
Actor.inv_remove_obj(target_actor, obj)
|
|
obj = nil
|
|
end
|
|
end
|
|
|
|
function gremlin_steal_item(target_actor)
|
|
local gremlin_items = { [0x80] = 1,
|
|
[0x81] = 1,
|
|
[0x82] = 1,
|
|
[0x83] = 1,
|
|
[0x84] = 1,
|
|
[0x85] = 1,
|
|
[0x87] = 1,
|
|
[0xD1] = 1,
|
|
[0xD2] = 1,
|
|
[0xD3] = 1 }
|
|
|
|
local obj = actor_select_obj_from_tbl(target_actor, gremlin_items)
|
|
|
|
if obj ~= nil then
|
|
play_sfx(SFX_FAILURE, true)
|
|
print("`"..target_actor.name.." has been robbed!\n")
|
|
Actor.inv_remove_obj(target_actor, obj)
|
|
obj = nil
|
|
end
|
|
end
|
|
|
|
function actor_take_hit(attacker, defender, max_dmg)
|
|
if attacker.obj_n == 357 then --corpser
|
|
attacker.frame_n = 1 --reveal corpser.
|
|
end
|
|
if max_dmg == -1 then
|
|
max_dmg = 1
|
|
elseif max_dmg > 1 and max_dmg ~= 255 then
|
|
max_dmg = math.random(1, max_dmg)
|
|
end
|
|
|
|
local ac
|
|
local defender_type = defender.luatype
|
|
if defender_type == "actor" then
|
|
ac = actor_get_ac(defender)
|
|
if max_dmg ~= 255 and ac > 0 then
|
|
max_dmg = max_dmg - math.random(1, ac)
|
|
end
|
|
--dgb("\nac = "..ac.."\n")
|
|
else
|
|
ac = 0 --object
|
|
end
|
|
if is_god_mode_enabled() then
|
|
if defender_type == "actor" and defender.in_party then
|
|
-- print("`"..defender.name.." grazed.\n")
|
|
return
|
|
elseif attacker.in_party then
|
|
max_dmg = 255
|
|
end
|
|
end
|
|
if max_dmg > 0 then
|
|
if defender_type == "actor" and defender.wt > 1 and defender.wt < 16 then
|
|
--FIXME defender now targets attacker. I think.
|
|
end
|
|
|
|
local exp_gained = actor_hit(defender, max_dmg, attacker)
|
|
|
|
attacker.exp = attacker.exp + exp_gained
|
|
else
|
|
print("`"..defender.name.." grazed.\n")
|
|
end
|
|
|
|
if defender_type == "actor" then
|
|
|
|
actor_yell_for_help(attacker, defender, max_dmg)
|
|
|
|
local defender_obj_n = defender.obj_n
|
|
|
|
if defender.alive == true
|
|
or defender_obj_n == 0x1a7 --balloon
|
|
or defender_obj_n == 0x19e --skiff
|
|
or defender_obj_n == 0x19f --raft
|
|
or defender_obj_n == 0x19c then --ship
|
|
|
|
local attacker_obj_n = attacker.obj_n
|
|
|
|
if attacker_obj_n == 0x165 then --corpser
|
|
play_sfx(SFX_CORPSER_DRAGGED_UNDER, true)
|
|
print("`"..defender.name.." dragged under!\n")
|
|
defender.corpser_flag = true
|
|
if defender.in_party == true then
|
|
party_update_leader()
|
|
end
|
|
end
|
|
|
|
if attacker_obj_n == 0x16c then --acid slug
|
|
acid_slug_dissolve_item(defender)
|
|
end
|
|
|
|
if attacker_obj_n == 0x161 then --gremlin
|
|
gremlin_steal_item(defender)
|
|
end
|
|
|
|
local actor_type = actor_tbl[attacker_obj_n]
|
|
if actor_type ~= nil and actor_type[15] == 1 and math.random(0, 3) == 0 and defender.actor_num ~= 0 then --actor is poisonous, don't poison vehicles.
|
|
defender.poisoned = true
|
|
print("`"..defender.name.." poisoned!\n")
|
|
end
|
|
|
|
if max_dmg > 0 then
|
|
actor_hit_msg(defender)
|
|
end
|
|
else
|
|
print("`"..defender.name.." killed!\n")
|
|
--FIXME do party roster change. maybe
|
|
end
|
|
|
|
end
|
|
end
|
|
|
|
function actor_hit(defender, max_dmg, attacker, no_hit_anim)
|
|
|
|
local defender_obj_n = defender.obj_n
|
|
local exp_gained = 0
|
|
|
|
if defender_obj_n == 0x1a7 then -- balloon.
|
|
return 0
|
|
end
|
|
|
|
if defender.luatype == "actor" then
|
|
if is_god_mode_enabled() then
|
|
if defender.in_party then
|
|
return 0
|
|
else
|
|
max_dmg = 255
|
|
end
|
|
end
|
|
--actor logic here
|
|
defender.hit_flag = true
|
|
if no_hit_anim == nil then
|
|
hit_anim(defender.x, defender.y)
|
|
end
|
|
if defender_obj_n == 409 then --lord british
|
|
defender.hp = 0xff
|
|
elseif defender_obj_n == 414 or defender_obj_n == 415 then --skiff, raft
|
|
-- hit random party member.
|
|
local num_in_party = party_get_size()
|
|
local party_member_num = 0
|
|
if num_in_party > 1 then
|
|
party_member_num = math.random(0, num_in_party - 1)
|
|
end
|
|
|
|
local rand_party_member = party_get_member(party_member_num)
|
|
actor_hit(rand_party_member, max_dmg, attacker, true)
|
|
actor_hit_msg(rand_party_member)
|
|
else
|
|
-- actor hit logic here
|
|
if max_dmg >= defender.hp then
|
|
|
|
if defender.hp ~= 0 then
|
|
if defender.in_party == true then player_subtract_karma(5) end --allowing your party to die is bad karma.
|
|
defender.hp = 0
|
|
-- defender.alive = false -- This doesn't work. The variable is get only
|
|
if alignment_is_evil(defender.align) then
|
|
local actor_base = actor_tbl[defender.obj_n]
|
|
if actor_base ~= nil then
|
|
--exp = (base_str + base_dex + base_int + base_hp + base_dmg + base_exp_gain) / 4
|
|
exp_gained = math.floor((actor_base[1] + actor_base[2] + actor_base[3] + actor_base[4] + actor_base[5] + actor_base[26]) / 4)
|
|
end
|
|
end
|
|
|
|
defender.visible = true
|
|
|
|
if defender.obj_n == 412 and defender.actor_num == 0 then --handle ship destruction
|
|
Actor.unlink_surrounding_objs(defender, true) --unlink ship front/back and make objects temporary.
|
|
defender.base_obj_n = 0x19f --raft
|
|
--try to toss raft out from center of the ship.
|
|
if actor_move(defender, DIR_NORTH, 1) == 0 then
|
|
if actor_move(defender, DIR_SOUTH, 1) == 0 then
|
|
if actor_move(defender, DIR_EAST, 1) == 0 then
|
|
actor_move(defender, DIR_WEST, 1)
|
|
end
|
|
end
|
|
end
|
|
defender.hp = 10
|
|
--defender.mpts = 1
|
|
party_move(defender.x, defender.y, defender.z)
|
|
else
|
|
actor_dead(defender)
|
|
|
|
defender.wt = WT_NOTHING
|
|
if defender.in_party == true and defender.in_vehicle == false then
|
|
party_update_leader()
|
|
end
|
|
end
|
|
end
|
|
else
|
|
defender.hp = defender.hp - max_dmg
|
|
if defender.wt == WT_FLEE then --flee
|
|
defender.wt = WT_ASSAULT --assault
|
|
end
|
|
if defender_obj_n == 375 then --slime
|
|
slime_divide(defender)
|
|
end
|
|
end
|
|
end
|
|
else
|
|
--object logic here
|
|
if defender_obj_n == 0x16e then -- tangle vine
|
|
--FIXME do something with tangle vine. -- I think the message is all that needed added
|
|
print("\nTangle vine killed!\n") -- The pod doesn't have this text in the original for some reason
|
|
elseif defender.stackable == false and defender.qty ~= 0 then
|
|
hit_anim(defender.x, defender.y)
|
|
if (defender_obj_n < 0x129 or defender_obj_n > 0x12c or defender.frame_n < 0xc) --check frame_n for door objects
|
|
and (defender_obj_n ~= 0x62 or defender.frame_n ~= 3) then --don't attack open chests
|
|
if defender.qty <= max_dmg then
|
|
print("\n`"..defender.name .. " broken!\n")
|
|
|
|
local child
|
|
for child in container_objs(defender) do -- look through container for effect object.
|
|
if child.obj_n == 0x151 then --effect
|
|
if attacker ~= nil then
|
|
actor_use_effect(attacker, child)
|
|
end
|
|
break
|
|
else
|
|
Obj.moveToMap(child, defender.x, defender.y, defender.z)
|
|
end
|
|
end
|
|
|
|
if defender_obj_n == 0x7b then --mirror
|
|
play_sfx(SFX_BROKEN_GLASS)
|
|
defender.frame_n = 2
|
|
player_subtract_karma(10)
|
|
else
|
|
map_remove_obj(defender)
|
|
end
|
|
else
|
|
defender.qty = defender.qty - max_dmg
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
return exp_gained
|
|
end
|
|
|
|
function actor_hit_msg(actor)
|
|
|
|
if actor.obj_n == 0x1a7 then return end --balloon
|
|
|
|
local hp = actor.hp
|
|
|
|
if hp == 0 then return end
|
|
|
|
local di = math.floor((hp * 4) / actor.max_hp)
|
|
|
|
local s
|
|
|
|
if di < 4 then
|
|
s = "\n`"..actor.name.." "
|
|
end
|
|
|
|
if di == 0 then
|
|
s = s.."critical!\n"
|
|
local wt = actor.wt
|
|
if actor_int_adj(actor) >= 5 and wt ~= WT_BERSERK and wt ~= WT_STATIONARY and wt > WT_FRONT then
|
|
actor.wt = WT_RETREAT
|
|
end
|
|
elseif di < 4 then
|
|
|
|
if di == 1 then
|
|
s = s.."heavily "
|
|
elseif di == 2 then
|
|
s = s.."lightly "
|
|
elseif di == 3 then
|
|
s = s.."barely "
|
|
end
|
|
s = s.."wounded.\n"
|
|
end
|
|
|
|
if s ~= nil then
|
|
print(s)
|
|
end
|
|
end
|
|
|
|
function actor_dead(actor)
|
|
local actor_base = actor_tbl[actor.obj_n]
|
|
if actor_base ~= nil then
|
|
if actor.obj_n == 0x163 then --gazer
|
|
Actor.new(0x157, actor.x, actor.y, actor.z) --insect
|
|
end
|
|
|
|
if actor_base[9] == 1 then --fades away. magical creature.
|
|
Actor.fade_out(actor, 20) --FIXME make fade speed configurable.
|
|
end
|
|
end
|
|
|
|
local in_vehicle = actor.in_vehicle
|
|
|
|
if in_vehicle == false and actor_base ~= nil and actor_base[8] == 1 or actor.obj_n == 0x187 or actor.obj_n == 0x188 then --farmer, musician
|
|
--add some blood.
|
|
--dgb("\nAdding Blood\n")
|
|
local blood_obj = Obj.new(0x152, math.random(0,2))
|
|
blood_obj.temporary = true
|
|
Obj.moveToMap(blood_obj, actor.x, actor.y, actor.z)
|
|
end
|
|
|
|
if actor.actor_num ~= 1 then --avatar
|
|
local create_body = true
|
|
if in_vehicle == true then
|
|
create_body = false -- don't drop body when party member dies on raft.
|
|
end
|
|
|
|
if actor_is_readiable_obj(actor) then
|
|
local animated_obj = Obj.new(actor.obj_n)
|
|
Obj.moveToMap(animated_obj, actor.x, actor.y, actor.z)
|
|
end
|
|
if actor.obj_n == 431 then --horse with rider
|
|
Actor.new(430, actor.x, actor.y, actor.z, ALIGNMENT_NEUTRAL, 12) --horse, wt wander
|
|
end
|
|
Actor.kill(actor, create_body)
|
|
else
|
|
actor.hp = 0 -- hackish way of making the Avatar not extinguish his torch
|
|
g_avatar_died = true
|
|
end
|
|
|
|
if actor.obj_n == 0x177 then
|
|
slime_update_frames()
|
|
end
|
|
end
|
|
|
|
function slime_divide(slime)
|
|
|
|
local random = math.random
|
|
local from_x, from_y, from_z = slime.x, slime.y, slime.z
|
|
local i
|
|
for i=1,8 do
|
|
|
|
local new_x = random(1, 2) + from_x - 1
|
|
local new_y = random(1, 2) + from_y - 1
|
|
|
|
if map_can_put(new_x, new_y, from_z) then
|
|
Actor.clone(slime, new_x, new_y, from_z)
|
|
slime_update_frames()
|
|
print("Slime divides!\n")
|
|
return
|
|
end
|
|
end
|
|
end
|
|
--[[
|
|
function bitor(x, y)
|
|
local p = 1
|
|
while p < x do p = p + p end
|
|
while p < y do p = p + p end
|
|
local z = 0
|
|
repeat
|
|
if p <= x or p <= y then
|
|
z = z + p
|
|
if p <= x then
|
|
x = x - p
|
|
end
|
|
if p <= y then y = y - p end
|
|
|
|
end
|
|
p = p * 0.5
|
|
until p < 1
|
|
return z
|
|
end
|
|
--]]
|
|
function slime_update_frames()
|
|
|
|
local i, j
|
|
local pow = math.pow
|
|
|
|
for i=1,0xff do
|
|
local actor = Actor.get(i)
|
|
if actor.obj_n == 0x177 and actor.alive then --slime
|
|
local new_frame_n = 0;
|
|
local idx = 0
|
|
for j = 1,8,2 do
|
|
local tmp_actor = map_get_actor(actor.x + movement_offset_x_tbl[j], actor.y + movement_offset_y_tbl[j], actor.z)
|
|
if tmp_actor ~= nil and tmp_actor.obj_n == 0x177 and tmp_actor.alive then
|
|
new_frame_n = new_frame_n + pow(2,idx)
|
|
end
|
|
idx = idx + 1
|
|
end
|
|
actor.frame_n = new_frame_n
|
|
end
|
|
end
|
|
end
|
|
|
|
function combat_range_check_target(actor_attacking)
|
|
|
|
if actor_attacking.wt > 1 and actor_attacking.wt < 0x10 then
|
|
--[[ FIXME
|
|
target = actor_attacking.target_obj
|
|
if target ~= actor_attacking then
|
|
|
|
if target.obj_n ~= 0 and target.alive == true and target.asleep == false and target.paralysed == false and target.corpser_flag == false then
|
|
|
|
if abs(actor_attacking.x - target.x) < 2 then
|
|
|
|
if abs(actor_attacking.y - target.y) < 2 and (time_stop_spell_timer == 0 or target.in_party == true) then
|
|
|
|
return false
|
|
end
|
|
end
|
|
end
|
|
end
|
|
--]]
|
|
end
|
|
|
|
return true
|
|
end
|
|
|
|
--check for arrows or bolts if attacking with a bow or crossbow
|
|
function out_of_ammo(attacker, weapon, print_message)
|
|
|
|
local weapon_obj_n = weapon.obj_n
|
|
|
|
if (weapon_obj_n == 41 or weapon_obj_n == 54) and Actor.inv_has_obj_n(attacker, 55) == false then --bow, magic bow, arrows
|
|
if(print_message) then
|
|
print("Out of arrows!\n")
|
|
end
|
|
return true --no arrows, bail out
|
|
end
|
|
if (weapon_obj_n == 42 or weapon_obj_n == 50) and Actor.inv_has_obj_n(attacker, 56) == false then --crossbow, triple crossbow, bolts
|
|
if(print_message) then
|
|
print("Out of bolts!\n")
|
|
end
|
|
return true --no bolts, bail out
|
|
end
|
|
return false
|
|
end
|
|
|
|
--
|
|
-- actor_attack(attacker, target, weapon)
|
|
--
|
|
|
|
function actor_attack(attacker, target_x, target_y, target_z, weapon, foe)
|
|
|
|
local random = math.random
|
|
local weapon_obj_n = weapon.obj_n
|
|
local weapon_quality = weapon.quality
|
|
|
|
if foe ~= nil and foe.actor_num == attacker.actor_num then
|
|
print("\n"..attacker.name.." is try to attack itself. Report me!\n") -- this shouldn't happen
|
|
return
|
|
end
|
|
|
|
if foe == nil then
|
|
foe = map_get_obj(target_x, target_y, target_z);
|
|
end
|
|
|
|
--dgb("\nactor_attack()\nrange = " .. get_attack_range(attacker.x,attacker.y, target_x, target_y).." weapon range="..get_weapon_range(weapon_obj_n))
|
|
if weapon_obj_n ~= attacker.obj_n then
|
|
--dgb("\nweapon = "..weapon.name.."obj_n = "..weapon_obj_n.."\n")
|
|
end
|
|
|
|
if Actor.get_range(attacker, target_x, target_y) > get_weapon_range(weapon_obj_n) then
|
|
return
|
|
end
|
|
|
|
--check for arrows or bolts if attacking with a bow or crossbow
|
|
|
|
if (out_of_ammo(attacker, weapon, false) == true) then
|
|
return --no arrows or bolts, bail out
|
|
end
|
|
|
|
|
|
local x_diff = target_x - attacker.x
|
|
local y_diff = target_y - attacker.y
|
|
local attacker_direction
|
|
|
|
if abs(x_diff) <= abs(y_diff) then
|
|
attacker_direction = (y_diff >= 0) and DIR_SOUTH or DIR_NORTH
|
|
else
|
|
attacker_direction = (x_diff >= 0) and DIR_EAST or DIR_WEST
|
|
end
|
|
|
|
local actor_obj_n = attacker.obj_n
|
|
--[[
|
|
if actor_obj_n == 0x19c then --ship
|
|
|
|
if(((*(&objlist_npc_movement_flags + actor_attacking) & 6 xor attacker_direction) & 2) == 0)
|
|
{
|
|
attacker_direction = attacker_direction xor 2;
|
|
}
|
|
else
|
|
{
|
|
attacker_direction = *(objlist_npc_movement_flags + actor_attacking) & 7;
|
|
}
|
|
end
|
|
--]]
|
|
|
|
if attacker.obj_n ~= 412 and actor_obj_n ~= 413 then --don't change direction for ship, silver serpent.
|
|
attacker.direction = attacker_direction
|
|
end
|
|
|
|
if actor_obj_n >= 0x170 and actor_obj_n <= 0x174 then -- skeleton, mongbat
|
|
local frame_n = attacker.frame_n
|
|
attacker.frame_n = (frame_n - (frame_n % 4)) + 2
|
|
end
|
|
|
|
|
|
local is_range_weapon = false
|
|
|
|
if weapon_obj_n ~= 40 and weapon_obj_n ~= 47 then -- morning star, halberd
|
|
if abs(x_diff) > 1 or abs(y_diff) > 1 or projectile_weapon_tbl[weapon_obj_n] ~= nil then
|
|
is_range_weapon = true
|
|
if combat_range_check_target(attacker) == false then return 1 end
|
|
end
|
|
end
|
|
|
|
local dmg = get_weapon_dmg(weapon_obj_n)
|
|
if dmg == nil then
|
|
dmg = 1
|
|
end
|
|
|
|
--FIXME run unknown func sub_1EABC here.
|
|
local player_loc = player_get_location()
|
|
|
|
if weapon_obj_n == 0x150 or weapon_obj_n == 0x39 then --charge, spellbook
|
|
|
|
if weapon_quality == 0x81 and actor_obj_n == 0x175 then -- special wisp magic (wisp teleport), wisp
|
|
|
|
if toss_actor(attacker, player_loc.x, player_loc.y, player_loc.z) == true then
|
|
|
|
print("Wisp teleports!\n")
|
|
end
|
|
|
|
return
|
|
end
|
|
|
|
local spell_retcode = 0
|
|
|
|
magic_cast_spell(weapon_quality, attacker, {x = target_x, y = target_y, z = target_z})
|
|
|
|
if weapon_quality == 0x50 and spell_retcode == 0xfe then
|
|
print("`"..foe.name .. " is charmed.\n")
|
|
elseif weapon_quality == 0x45 and spell_retcode == 0 then
|
|
print("`"..foe.name .. " is paralyzed.\n")
|
|
end
|
|
|
|
return
|
|
end
|
|
|
|
|
|
--weapon here.
|
|
|
|
local hit_actor = actor_combat_hit_check(attacker, foe, weapon)
|
|
local num_bolts
|
|
local missed_target = false
|
|
|
|
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
|
|
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
|
|
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)
|
|
|
|
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)
|
|
|
|
|
|
else --standard weapon
|
|
if actor_find_max_xy_distance(attacker, player_loc.x, player_loc.y) < 6 then
|
|
--play_sound_effect(0x11, 0);
|
|
play_sfx(SFX_ATTACK_SWING, true)
|
|
end
|
|
end
|
|
|
|
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
|
|
|
|
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
|
|
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
|
|
end
|
|
end
|
|
|
|
end
|
|
else
|
|
|
|
if hit_actor == true then
|
|
|
|
local actor_base = actor_tbl[foe.obj_n]
|
|
if actor_base ~= nil and actor_base[14] == 1 -- takes half dmg
|
|
and weapon_obj_n ~= 0x30 and weapon_obj_n ~= 0x32 and weapon_obj_n ~= 0x36 then --glass sword, triple crossbow, magic bow
|
|
dmg = math.floor((dmg + 1) / 2)
|
|
end
|
|
|
|
if weapon_obj_n ~= 0x5b then --Zu Ylem
|
|
actor_take_hit(attacker, foe, dmg)
|
|
end
|
|
|
|
if weapon_obj_n == 0x30 then
|
|
print("Thy sword hath shattered!\n")
|
|
Actor.inv_remove_obj(attacker, weapon)
|
|
end
|
|
end
|
|
|
|
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])
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
function combat_range_weapon_1D5F9(attacker, target_x, target_y, target_z, foe, weapon)
|
|
|
|
local weapon_obj_n = weapon.obj_n
|
|
local random = math.random
|
|
|
|
if weapon_obj_n == 0x32 then --triple cross bow
|
|
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])
|
|
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
|
|
|
|
if weapon_obj_n == 0x5b then
|
|
--Zu Ylem
|
|
if foe ~= nil and foe.obj_n ~= 0 then
|
|
Actor.inv_remove_obj_qty(attacker, 0x5b, 1)
|
|
spell_put_actor_to_sleep(attacker, foe)
|
|
end
|
|
elseif weapon_obj_n == 0x4f or weapon_obj_n == 0x50 then
|
|
--lightning wand, fire wand
|
|
if random(1, 100) == 37 then
|
|
Actor.inv_remove_obj(attacker, weapon)
|
|
print("A wand has vanished!\n")
|
|
end
|
|
elseif weapon_obj_n == 0x53 then
|
|
--flask of oil
|
|
|
|
Actor.inv_remove_obj_qty(attacker, 0x53, 1)
|
|
|
|
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)
|
|
end
|
|
|
|
elseif weapon_obj_n == 0x24 or weapon_obj_n == 0x25 or weapon_obj_n == 0x26 then
|
|
--spear, throwing axe, dagger
|
|
|
|
if Actor.inv_remove_obj_qty(attacker, weapon_obj_n, 1) == 1 and 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
|
|
|
|
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
|
|
local projectile_obj = nil
|
|
if weapon_obj_n == 0x29 or weapon_obj_n == 0x36 then --bow, magic bow
|
|
projectile_obj = 0x37 --arrow
|
|
else
|
|
projectile_obj = 0x38 --bolt
|
|
end
|
|
|
|
local qty = 1
|
|
if weapon_obj_n == 0x32 then -- triple crossbow
|
|
qty = 3
|
|
end
|
|
|
|
Actor.inv_remove_obj_qty(attacker, projectile_obj, qty)
|
|
end
|
|
|
|
return 1
|
|
end
|
|
|
|
--
|
|
-- actor_get_weapon()
|
|
--
|
|
function actor_get_weapon(attacker, foe)
|
|
|
|
if foe == nil then return nil end
|
|
|
|
local in_party = attacker.in_party
|
|
local range = Actor.get_range(attacker, foe.x, foe.y)
|
|
--dgb("range = "..range.."\n")
|
|
local max_dmg = 0
|
|
local obj, weapon
|
|
|
|
for obj in actor_inventory(attacker) do
|
|
if obj.obj_n == 336 and timer_get(TIMER_STORM) == 0 and math.random(0,3) == 0 and math.random(0, obj.quality) < 16 then --charge (spell)
|
|
--dgb("magic object quality = "..obj.quality.."\n");
|
|
return obj
|
|
else
|
|
if in_party == false or obj.readied == true then
|
|
local dmg = get_weapon_dmg(obj.obj_n)
|
|
if dmg ~= nil and dmg > max_dmg and get_weapon_range(obj.obj_n) >= range then
|
|
max_dmg = dmg
|
|
weapon = obj
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
if weapon == nil then --attack with bare hands.
|
|
weapon = attacker
|
|
end
|
|
|
|
--dgb("weapon: "..weapon.name.." dmg="..get_weapon_dmg(weapon.obj_n).."\n")
|
|
|
|
return weapon
|
|
end
|
|
|
|
--
|
|
-- actor_calculate_avg_coords()
|
|
--
|
|
function actor_calculate_avg_coords()
|
|
local n = 0
|
|
local avg_x = 0
|
|
local avg_y = 0
|
|
|
|
local player_loc = player_get_location()
|
|
|
|
local player_x = player_loc.x
|
|
local player_y = player_loc.y
|
|
|
|
local player = Actor.get_player_actor()
|
|
local player_dir = player.direction
|
|
|
|
local actor
|
|
for actor in party_members() do
|
|
if actor.wt ~= WT_FLANK and actor.wt ~= WT_BERSERK then
|
|
n = n + 1
|
|
avg_x = avg_x + actor.x
|
|
avg_y = avg_y + actor.y
|
|
end
|
|
end
|
|
|
|
if n > 0 then
|
|
party_avg_x = math.floor(avg_x / n)
|
|
party_avg_y = math.floor(avg_y / n)
|
|
else
|
|
party_avg_x = player_x
|
|
party_avg_y = player_y
|
|
end
|
|
|
|
n = 0
|
|
avg_x = 0
|
|
avg_y = 0
|
|
|
|
local i
|
|
for i=0,0xff do
|
|
actor = Actor.get(i)
|
|
|
|
if actor.obj_n ~= 0 and actor.alive then
|
|
|
|
if (actor.align == ALIGNMENT_EVIL or actor.align == ALIGNMENT_CHAOTIC) then
|
|
if actor.wt ~= WT_RETREAT or (abs(actor.x - player_x) <= 5 and abs(actor.y - player_y) <= 5) then
|
|
if abs(actor.x - player_x) < 0x18 and abs(actor.y - player_y) < 0x18 then
|
|
n = n + 1
|
|
avg_x = avg_x + actor.x
|
|
avg_y = avg_y + actor.y
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
wt_num_monsters_near = n
|
|
|
|
if n > 0 then
|
|
combat_avg_x = math.floor((avg_x + n / 2) / n)
|
|
combat_avg_y = math.floor((avg_y + n / 2) / n)
|
|
|
|
wt_rear_max_monster = nil
|
|
wt_rear_min_monster = nil
|
|
--wt_rear_max_party = nil
|
|
--wt_rear_min_party = nil
|
|
|
|
local tmp_x = combat_avg_x - party_avg_x
|
|
local tmp_y = combat_avg_y - party_avg_y
|
|
|
|
wt_front_target_actor = nil
|
|
local min_m_pos = 0
|
|
local max_m_pos = 0
|
|
local min_p_pos = 0
|
|
local max_p_pos = 0
|
|
--var_16 = 0x8000
|
|
|
|
local var_A
|
|
for i=0,0xff do
|
|
actor = Actor.get(i)
|
|
if actor.obj_n ~= 0 and actor.alive and (actor.wt == WT_FRONT or actor.wt == WT_PLAYER) then
|
|
--var_C = ((actor.x - party_avg_x) * tmp_x) + ((actor.y - party_avg_y) * tmp_y)
|
|
var_A = ((actor.x - party_avg_x) * tmp_y) - ((actor.y - party_avg_y) * tmp_x)
|
|
-- --dgb("ok "..actor.name.."\n")
|
|
if actor.in_party == false then
|
|
if wt_front_target_actor == nil then wt_front_target_actor = actor end
|
|
if var_A > max_m_pos then max_m_pos, wt_rear_max_monster = var_A, actor end
|
|
if var_A < min_m_pos then min_m_pos, wt_rear_min_monster = var_A, actor end
|
|
else
|
|
--dgb("yup var_A["..i.."] = "..var_A.."\n")
|
|
if var_A > max_p_pos then
|
|
--dgb("var_A > max_p_pos\n")
|
|
max_p_pos, wt_rear_max_party = var_A, actor
|
|
end
|
|
if var_A < min_p_pos then
|
|
--dgb("var_A < min_p_pos\n")
|
|
min_p_pos, wt_rear_min_party = var_A, actor
|
|
end
|
|
--if var_C > var_16 then var_16, unk_3DEAD = var_C, actor end
|
|
end
|
|
end
|
|
end
|
|
--FIXME I'm not really sure what the original does when these aren't set
|
|
if wt_rear_max_party == nil then wt_rear_max_party = player end
|
|
if wt_rear_min_party == nil then wt_rear_min_party = player end
|
|
else
|
|
--this is used by party members when in combat_front worktype.
|
|
combat_avg_x = player_x + movement_offset_x_tbl[(player_dir*2) + 1]
|
|
combat_avg_y = player_y + movement_offset_y_tbl[(player_dir*2) + 1]
|
|
end
|
|
|
|
if combat_avg_x == party_avg_x and combat_avg_y == party_avg_y then
|
|
combat_avg_x = combat_avg_x + movement_offset_x_tbl[(player_dir*2) + 1]
|
|
combat_avg_y = combat_avg_y + movement_offset_y_tbl[(player_dir*2) + 1]
|
|
end
|
|
--dgb("PartyAvg("..party_avg_x..","..party_avg_y..") CombatAvg("..combat_avg_x..","..combat_avg_y..") Player("..player_x..","..player_y..") Dir = "..player_dir.." numMonsters = "..wt_num_monsters_near.."\n")
|
|
end
|
|
--[[
|
|
function trace (event, line)
|
|
local s = debug.getinfo(2).name
|
|
if s == nil then
|
|
s = "Unk"
|
|
end
|
|
--io.stderr:write(s .. ":" .. line.."\n")
|
|
end
|
|
|
|
debug.sethook(trace, "l")
|
|
--]]
|
|
|
|
--
|
|
-- actor_update_all()
|
|
--
|
|
function actor_update_all()
|
|
--dgb("actor_update_all()\n")
|
|
if g_avatar_died == true then
|
|
actor_avatar_death()
|
|
return
|
|
end
|
|
g_time_stopped = is_time_stopped()
|
|
|
|
actor_calculate_avg_coords()
|
|
local actor
|
|
local selected_actor
|
|
repeat
|
|
selected_actor = nil
|
|
local di = 0
|
|
local dex_6 = 1
|
|
repeat
|
|
local player_loc = player_get_location()
|
|
local var_C = (player_loc.x - 16) - (player_loc.x - 16) % 8
|
|
local var_A = (player_loc.y - 16) - (player_loc.y - 16) % 8
|
|
|
|
for actor in party_members() do
|
|
if actor.wt == WT_FOLLOW and actor.mpts < 0 then
|
|
actor.mpts = 0
|
|
end
|
|
end
|
|
|
|
local player_z = player_loc.z
|
|
for i=0,0xff do
|
|
local actor = Actor.get(i)
|
|
if actor.obj_n ~= 0 and actor.z == player_z and actor.mpts > 0 and actor.paralyzed == false and actor.asleep == false and actor.wt ~= WT_NOTHING and actor.alive == true then
|
|
if abs(actor.x - var_C) > 0x27 or abs(actor.y - var_A) > 0x27 then
|
|
if actor.wt >= 0x83 and actor.wt <= 0x86 then
|
|
--move actor to schedule location if it isn't on screen
|
|
local sched_loc = actor.sched_loc
|
|
if map_is_on_screen(sched_loc.x, sched_loc.y, sched_loc.z) == false then
|
|
Actor.move(actor, sched_loc.x, sched_loc.y, sched_loc.z)
|
|
actor_wt_walk_to_location(actor) --this will cancel the pathfinder and set the new worktype
|
|
subtract_movement_pts(actor, 10)
|
|
----dgb("\nActor SCHEDULE TELEPORT "..actor.actor_num.." to ("..sched_loc.x..","..sched_loc.y..","..sched_loc.z..")\n")
|
|
end
|
|
end
|
|
else
|
|
if actor.wt ~= WT_FOLLOW then
|
|
if actor.wt == 0x80 then
|
|
-- actor_set_worktype_from_schedule(actor)
|
|
actor.wt = actor.sched_wt
|
|
end
|
|
|
|
local dx = (actor.mpts * dex_6) - actor.dex * di
|
|
if actor.mpts >= actor.dex or dx > 0 or dx == 0 and actor.dex > dex_6 then
|
|
selected_actor = actor
|
|
di = actor.mpts
|
|
dex_6 = actor.dex
|
|
end
|
|
|
|
if actor.mpts >= actor.dex then
|
|
break
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
if di <= 0 then
|
|
advance_time(1)
|
|
end
|
|
until di > 0
|
|
|
|
if selected_actor.corpser_flag == true then
|
|
actor_corpser_regurgitation(selected_actor)
|
|
end
|
|
|
|
if selected_actor.corpser_flag == false then
|
|
if selected_actor.wt ~= WT_PLAYER and selected_actor.wt ~= WT_FOLLOW then
|
|
--dgb("perform_worktype("..selected_actor.name.."("..selected_actor.actor_num..") dex = "..selected_actor.dex.." mpts = "..selected_actor.mpts..").\n")
|
|
perform_worktype(selected_actor)
|
|
--sub_1C34A() --update map window??
|
|
if selected_actor.wt > 1 and selected_actor.wt < 0x10 then
|
|
--FIXME targetting?? do *(&objlist_ptr_unk_18f1 + actor_num) = actor_num
|
|
end
|
|
end
|
|
|
|
--sub_4726()
|
|
end
|
|
|
|
until selected_actor.obj_n ~= 0 and selected_actor.wt == WT_PLAYER and selected_actor.corpser_flag == false
|
|
|
|
if selected_actor ~= nil then --swap player to next party member with 'command' combat worktype.
|
|
local old_player = Actor.get_player_actor()
|
|
player_set_actor(selected_actor)
|
|
old_player.wt = WT_PLAYER --reset worktype to player as it gets changed to follow in Player::set_actor() :-(
|
|
end
|
|
|
|
if g_update_volcano == true then
|
|
local obj = find_volcano_near_player()
|
|
if obj ~= nil then
|
|
if obj.obj_n == 307 then --volcano
|
|
play_sfx(SFX_EARTH_QUAKE, false)
|
|
quake_start(1,200)
|
|
else
|
|
local temp_fumarole = Obj.new(obj) --duplicate the fumarole object so we can explode it.
|
|
explode_obj(temp_fumarole)
|
|
end
|
|
end
|
|
g_update_volcano = false
|
|
end
|
|
|
|
display_prompt(true)
|
|
end
|
|
|
|
function advance_time(num_turns)
|
|
local teleport = num_turns >= 60
|
|
--dgb("advance_time("..num_turns..")")
|
|
local time_stop_timer = timer_get(TIMER_TIME_STOP)
|
|
|
|
if time_stop_timer ~= 0 then
|
|
if time_stop_timer > num_turns then
|
|
timer_set(TIMER_TIME_STOP, time_stop_timer - num_turns)
|
|
return
|
|
end
|
|
|
|
timer_set(TIMER_TIME_STOP, 0)
|
|
end
|
|
|
|
timer_update_all(num_turns)
|
|
|
|
--update keg timer. explode kegs.
|
|
if g_keg_timer > 0 then
|
|
g_keg_timer = g_keg_timer - num_turns
|
|
if g_keg_timer <= 0 then
|
|
explode_keg()
|
|
g_keg_timer = 0
|
|
end
|
|
end
|
|
|
|
local random = math.random
|
|
local cloak_readied = false
|
|
local i
|
|
for i=0,0xff do
|
|
local actor = Actor.get(i)
|
|
|
|
if actor.obj_n ~= 0 then
|
|
|
|
if actor.mpts >= 0 then
|
|
m = actor.dex
|
|
else
|
|
m = actor.mpts + actor.dex
|
|
end
|
|
|
|
actor.mpts = m
|
|
if actor.wt == WT_FOLLOW and actor.corpser_flag == true then
|
|
actor_corpser_regurgitation(actor) --hack the original does this in party_move() but we don't have that in script yet.
|
|
end
|
|
|
|
if actor.in_party == true then
|
|
local obj
|
|
for obj in actor_inventory(actor) do
|
|
if obj.readied == true then
|
|
local obj_n = obj.obj_n
|
|
local obj_name = nil
|
|
if obj_n == 0x5a and obj.frame_n == 1 then --lit torch
|
|
if random(0, 1) == 0 then
|
|
if obj.qty > num_turns then
|
|
obj.qty = obj.qty - num_turns
|
|
else
|
|
--print("A torch burned out.\n")
|
|
Actor.inv_unready_obj(actor, obj)
|
|
end
|
|
end
|
|
elseif obj_n == 0x102 then --invisibility ring
|
|
if random(0, 1000) == 429 then
|
|
local two_rings = (Actor.inv_get_readied_obj_n(actor, 5) == 0x102
|
|
and Actor.inv_get_readied_obj_n(actor, 6) == 0x102)
|
|
if two_rings == false then
|
|
actor.visible = true
|
|
end
|
|
obj_name = "ring"
|
|
end
|
|
elseif obj_n == 0x101 then -- regeneration ring
|
|
--FIXME the original increments a counter here.
|
|
local hp = actor.hp + num_turns
|
|
local max_hp = actor.max_hp
|
|
if hp > max_hp then
|
|
hp = max_hp
|
|
end
|
|
actor.hp = hp
|
|
|
|
if random(0, 1000) == 734 then
|
|
obj_name = "ring"
|
|
end
|
|
elseif obj_n == 0x51 then --storm cloak
|
|
if random(0, 1000) == 588 then
|
|
obj_name = "cloak"
|
|
timer_set(TIMER_STORM, 0)
|
|
else
|
|
cloak_readied = true
|
|
end
|
|
end
|
|
|
|
if obj_name ~= nil then
|
|
Actor.inv_remove_obj(actor, obj)
|
|
print("A "..obj_name.." has vanished!\n")
|
|
end
|
|
end
|
|
end
|
|
end
|
|
local j
|
|
for j=1,num_turns do
|
|
actor_update_flags(actor)
|
|
end
|
|
|
|
actor_map_dmg(actor, actor.x, actor.y, actor.z)
|
|
actor.hit_flag = false
|
|
end
|
|
end
|
|
|
|
if cloak_readied == true then
|
|
timer_set(TIMER_STORM, 1)
|
|
end
|
|
|
|
local minute = clock_get_minute()
|
|
|
|
clock_inc(num_turns)
|
|
|
|
if minute + num_turns >= 60 then
|
|
|
|
update_actor_schedules(teleport)
|
|
|
|
--update magic points
|
|
local party_actor
|
|
for party_actor in party_members() do
|
|
local max_magic = actor_get_max_magic_points(party_actor)
|
|
if max_magic ~= 0 then -- Avatar, Mage, Swashbuckler, Musician
|
|
local magic_pts = party_actor.magic + party_actor.level
|
|
if magic_pts > max_magic then
|
|
magic_pts = max_magic
|
|
end
|
|
party_actor.magic = magic_pts
|
|
end
|
|
end
|
|
|
|
player_dec_alcohol(1)
|
|
end
|
|
if g_avatar_died == true then
|
|
actor_avatar_death()
|
|
end
|
|
|
|
if random(0,7) == 0 then
|
|
g_update_volcano = true
|
|
end
|
|
end
|
|
|
|
function actor_update_flags(actor)
|
|
|
|
local random = math.random
|
|
|
|
if actor.alive then
|
|
local var_8 = 0 --FIXME get proper value for var_8.
|
|
if actor.visible == false and var_8 == 0 and random(0, 0x3f) == 0
|
|
and Actor.inv_get_readied_obj_n(actor, 5) ~= 0x102 --invisibility rings
|
|
and Actor.inv_get_readied_obj_n(actor, 6) ~= 0x102 then
|
|
if actor_int_adj(actor) <= random(1, 0x1e) then
|
|
actor.visible = true
|
|
end
|
|
end
|
|
|
|
if actor.protected == true and random(0, 0x3f) == 0 then
|
|
if actor_int_adj(actor) <= random(1, 0x1e) then
|
|
actor.protected = false
|
|
end
|
|
end
|
|
|
|
if actor.cursed == true and random(0, 15) == 0 then
|
|
if actor_int_adj(actor) >= random(1, 0x1e) then
|
|
actor.cursed = false
|
|
end
|
|
end
|
|
|
|
if actor.charmed == true and random(0, 7) == 0 then
|
|
if actor_int_adj(actor) >= random(1, 0x1e) then
|
|
actor_remove_charm(actor)
|
|
end
|
|
end
|
|
|
|
if actor.paralyzed == true and random(0, 3) == 0 then
|
|
if actor_str_adj(actor) >= random(1, 0x1e) then
|
|
actor.paralyzed = false
|
|
party_update_leader()
|
|
end
|
|
end
|
|
|
|
if actor.asleep == true and actor.wt ~= WT_SLEEP and random(0, 15) == 0 then
|
|
actor.asleep = false
|
|
actor.hit_flag = true
|
|
actor.frame_n = actor.old_frame_n
|
|
if actor.in_party == true then
|
|
party_update_leader()
|
|
end
|
|
end
|
|
|
|
if actor.poisoned == true and actor.protected == false and random(0, 7) == 0 then
|
|
if map_is_on_screen(actor.x, actor.y, actor.z) == true then
|
|
actor_hit(actor, 1)
|
|
else -- don't show the animation or play the sfx
|
|
actor_hit(actor, 1, nil, true)
|
|
end
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
function actor_corpser_regurgitation(actor)
|
|
--dgb("actor_corpser_regurgitation("..actor.name..")\n");
|
|
if actor.corpser_flag == false then return end
|
|
|
|
if actor.wt == WT_PLAYER then
|
|
print("\n"..actor.name..":\nARGH!\n")
|
|
end
|
|
|
|
local random = math.random
|
|
local val = random(1, 0x1e)
|
|
|
|
if val < actor_str_adj(actor) then
|
|
play_sfx(SFX_CORPSER_REGURGITATE, true)
|
|
print("`"..actor.name.." regurgitated!\n")
|
|
actor.corpser_flag = false
|
|
if actor.in_party == true then
|
|
party_update_leader()
|
|
end
|
|
else
|
|
actor_hit(actor, random(1, 0xf))
|
|
actor.mpts = 0
|
|
end
|
|
|
|
end
|
|
|
|
function actor_remove_charm(actor)
|
|
|
|
if actor.charmed == true then
|
|
actor.charmed = false;
|
|
actor.align = actor.old_align
|
|
|
|
if actor.in_party == true then
|
|
actor.align = ALIGNMENT_GOOD
|
|
end
|
|
party_update_leader()
|
|
--[[ FIXME need to add functions to check for combat_mode and solo_mode
|
|
if party_in_combat_mode() then
|
|
actor.wt = combat_mode
|
|
else
|
|
if solo_mode() then
|
|
actor.wt = WT_NOTHING
|
|
else
|
|
actor.wt = WT_FOLLOW
|
|
end
|
|
end
|
|
--]]
|
|
return true
|
|
end
|
|
|
|
return false
|
|
end
|
|
|
|
function actor_yell_for_help(attacking_actor, defending_actor, dmg)
|
|
|
|
if defending_actor.hp == 0 then
|
|
return
|
|
end
|
|
|
|
if defending_actor.luatype == "actor" and defending_actor.align == ALIGNMENT_NEUTRAL and defending_actor.in_party == false then
|
|
local actor_base = actor_tbl[defending_actor.obj_n]
|
|
|
|
if attacking_actor.wt == WT_PLAYER and actor_base ~= nil then
|
|
if actor_base[7] ~= 0 and dmg > 0 then --[7] == can_talk
|
|
print("`"..defending_actor.name.." yells for help!\n")
|
|
activate_city_guards()
|
|
end
|
|
end
|
|
|
|
if defending_actor.wt >= 0x80 then
|
|
if attacking_actor.wt == WT_PLAYER then
|
|
if defending_actor.obj_n == 0x188 then -- musician
|
|
defending_actor.frame_n = defending_actor.old_frame_n
|
|
end
|
|
defending_actor.wt = WT_ATTACK_PARTY
|
|
end
|
|
|
|
else
|
|
|
|
if attacking_actor.align ~= ALIGNMENT_GOOD then
|
|
defending_actor.align = ALIGNMENT_GOOD
|
|
else
|
|
defending_actor.align = ALIGNMENT_CHAOTIC
|
|
end
|
|
|
|
if defending_actor.temp == true then
|
|
defending_actor.wt = WT_ASSAULT
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
function can_get_obj_override(obj) --meat, ribs, dead animal. These are toptile objects and need an override check.
|
|
if obj.obj_n == 209 or obj.obj_n == 210 or obj.obj_n == 211 then
|
|
return true
|
|
end
|
|
return false
|
|
end
|
|
|
|
function actor_get_obj(actor, obj)
|
|
|
|
if obj.getable == false then
|
|
print("\n\nNot possible.")
|
|
return false
|
|
end
|
|
|
|
if Actor.can_carry_obj_weight(actor, obj) == false then
|
|
print("\n\nThe total is too heavy.")
|
|
return false
|
|
end
|
|
|
|
local player_loc = player_get_location()
|
|
local i
|
|
local caught_stealing = false
|
|
if player_loc.z == 0 and obj.ok_to_take == false then --stealing logic only applies to surface level.
|
|
player_subtract_karma(1)
|
|
play_sfx(SFX_FAILURE, true)
|
|
for i=1,202 do --perm actors
|
|
local actor = Actor.get(i)
|
|
|
|
if actor.alive == true and actor.z == player_loc.z and actor.in_party == false and actor.align == ALIGNMENT_NEUTRAL and actor.asleep == false then
|
|
if actor_find_max_xy_distance(actor, player_loc.x, player_loc.y) < 0x6 then
|
|
print("\n\n\"Stop Thief!!!\"\n")
|
|
activate_city_guards()
|
|
caught_stealing = true
|
|
break
|
|
end
|
|
end
|
|
end
|
|
|
|
if caught_stealing == false then
|
|
print("\n\nStealing!!!\n")
|
|
end
|
|
end
|
|
|
|
obj.ok_to_take = true
|
|
|
|
Obj.moveToInv(obj, actor.actor_num)
|
|
subtract_movement_pts(actor, 3)
|
|
|
|
return true
|
|
end
|
|
|
|
function activate_city_guards()
|
|
--dgb("activate_city_guards()")
|
|
local i
|
|
local player_loc = player_get_location()
|
|
|
|
player_subtract_karma(5)
|
|
|
|
for i=1,0xff do
|
|
local actor = Actor.get(i)
|
|
|
|
if actor.alive == true and actor.z == player_loc.z and actor.in_party == false and actor.align == ALIGNMENT_NEUTRAL then
|
|
if actor.obj_n == 0x17e then -- guard
|
|
if actor_find_max_xy_distance(actor, player_loc.x, player_loc.y) < 0x20 then
|
|
actor.wt = WT_GUARD_ARREST_PLAYER
|
|
end
|
|
else
|
|
if actor.wt ~= WT_STATIONARY
|
|
and actor.wt ~= WT_NOTHING
|
|
and actor.wt ~= WT_PLAYER
|
|
and actor.paralyzed == false
|
|
and actor.asleep == false
|
|
and actor.corpser_flag == false then
|
|
if actor_find_max_xy_distance(actor, player_loc.x, player_loc.y) < 0x6 then
|
|
if actor.wt < 0x80 then
|
|
actor.wt = WT_UNK_13
|
|
else
|
|
if actor.wt > 0x86 then
|
|
if actor.obj_n == 0x188 then
|
|
actor.frame_n = actor.old_frame_n
|
|
end
|
|
actor.wt = WT_ATTACK_PARTY
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function actor_catch_up_to_party(actor)
|
|
local target_actor = nil
|
|
local actor_x = actor.x
|
|
local actor_y = actor.y
|
|
local var_2 = 0x32
|
|
local party_actor
|
|
local random = math.random
|
|
|
|
for party_actor in party_members() do
|
|
|
|
if party_actor.alive == true and actor_ok_to_attack(actor, party_actor) == true then
|
|
|
|
local party_actor_x = party_actor.x
|
|
local party_actor_y = party_actor.y
|
|
local var_4 = (party_actor_x - actor_x) * (party_actor_x - actor_x) + (party_actor_y - actor_y) * (party_actor_y - actor_y)
|
|
if var_4 < var_2 or var_4 == var_2 and random(0, 1) ~= 0 then
|
|
var_2 = var_4
|
|
target_actor = party_actor
|
|
end
|
|
end
|
|
end
|
|
|
|
if target_actor == nil then
|
|
actor_move_towards_loc(actor, party_avg_x, party_avg_y)
|
|
return false
|
|
end
|
|
|
|
actor_move_towards_loc(actor, target_actor.x, target_actor.y)
|
|
|
|
if abs(target_actor.x - actor.x) > 1 or abs(target_actor.y - actor.y) > 1 then
|
|
return false
|
|
end
|
|
|
|
return true --reached party
|
|
end
|
|
|
|
function caught_by_guard(actor)
|
|
|
|
local lord_british = Actor.get(6)
|
|
|
|
--FIXME we don't want people going to jail before they answer the copy protection questions.
|
|
--if (objlist_talk_flags[5] & 0x80) == 0 then
|
|
-- actor.wt = 0x81
|
|
-- return
|
|
--end
|
|
|
|
Actor.show_portrait(actor)
|
|
|
|
print("\n\"Thou art under arrest!\"\n\n\"Wilt thou come quietly?\"\n\n:")
|
|
|
|
local var_6 = input_select("yn", false)
|
|
|
|
actor.wt = 0x81
|
|
|
|
Actor.hide_portrait()
|
|
|
|
if var_6 == "Y" then
|
|
print("es\n\nThe guard strikes thee unconscious!\n\nThou dost awaken to...\n")
|
|
--sub_2ACA1()
|
|
|
|
fade_out()
|
|
|
|
if party_is_in_combat_mode() then
|
|
party_set_combat_mode(false)
|
|
end
|
|
|
|
player_move(0xe7, 0xba, 0, true)
|
|
|
|
local cur_hour = clock_get_hour()
|
|
while cur_hour ~= 8 do
|
|
advance_time(60)
|
|
cur_hour = clock_get_hour()
|
|
--FIXME need to pause and update screen so player can see the sun-moon display move.
|
|
end
|
|
|
|
for party_actor in party_members() do
|
|
for var_4 in actor_inventory(party_actor, true) do -- recursively search containers in inventory.
|
|
--if((*(var_4 + objlist_obj_flags) & 0x18) == 0 || sub_CC5E(var_4, *(di + objlist_party_roster)) == 0)
|
|
-- break
|
|
|
|
if var_4.obj_n == 0x3f then --lockpick
|
|
Actor.inv_remove_obj(party_actor, var_4)
|
|
end
|
|
|
|
if var_4.obj_n == 0x40 and var_4.quality == 9 then --key
|
|
|
|
local obj = map_get_obj(0xeb, 0xb7, 0, 0xb1) --desk
|
|
if obj ~= nil then
|
|
Obj.moveToCont(var_4, obj)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local obj = map_get_obj(0xe7, 0xb8, 0, 0x12c) --steal door
|
|
if obj ~= nil then
|
|
obj.frame_n = 9 --close and lock door.
|
|
end
|
|
|
|
fade_in()
|
|
|
|
--[[
|
|
word_31D08 = 1
|
|
sub_E5F2()
|
|
music_play_song()
|
|
ax = sub_46DC()
|
|
--]]
|
|
else
|
|
|
|
print("o\n\n\"Then defend thyself, rogue!\"\n")
|
|
activate_city_guards()
|
|
actor.wt = WT_ASSAULT
|
|
actor.align = ALIGNMENT_EVIL
|
|
|
|
local i
|
|
for i=1,0xff do
|
|
local a = Actor.get(i)
|
|
if a.wt == WT_GUARD_ARREST_PLAYER then
|
|
a.wt = WT_ASSAULT
|
|
a.align = ALIGNMENT_EVIL
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
return
|
|
end
|
|
|
|
local tangle_vine_frame_n_tbl = {
|
|
1, 3, 1, 4,
|
|
5, 0, 4, 0,
|
|
1, 2, 1, 5,
|
|
2, 0, 3, 0
|
|
}
|
|
|
|
function move_tanglevine(actor, new_direction)
|
|
local actor_x = actor.x
|
|
local actor_y = actor.y
|
|
local old_direction = actor.direction
|
|
|
|
if new_direction ~= direction_reverse(old_direction) then
|
|
|
|
if actor_move(actor, new_direction, 1) ~= 0 then
|
|
local player_loc = player_get_location()
|
|
|
|
local tangle_obj = Obj.new(0x16e) --tanglevine
|
|
|
|
tangle_obj.frame_n = tangle_vine_frame_n_tbl[old_direction * 4 + new_direction + 1]
|
|
tangle_obj.status = 0x20
|
|
tangle_obj.quality = 0 --actor.id_n
|
|
|
|
Obj.moveToMap(tangle_obj, actor_x, actor_y, player_loc.z)
|
|
|
|
actor.frame_n = tangle_vine_frame_n_tbl[new_direction * 4 + math.random(0, 3) + 1]
|
|
|
|
return true
|
|
end
|
|
end
|
|
|
|
return false
|
|
end
|
|
|
|
function actor_wt_front(actor)
|
|
--dgb("actor_wt_front("..actor.name..")\n")
|
|
if actor_wt_front_1FB6E(actor) ~= 0 then
|
|
if actor.in_party == true then
|
|
actor_wt_attack(actor)
|
|
else
|
|
if actor_find_max_xy_distance(actor, party_avg_x, party_avg_y) >= 8 then
|
|
subtract_movement_pts(actor, 5)
|
|
else
|
|
if actor ~= wt_front_target_actor then
|
|
actor_wt_attack(actor)
|
|
else
|
|
if math.random(0, 7) ~= 0 then
|
|
actor_wt_attack(actor)
|
|
else
|
|
actor_move_towards_loc(actor, party_avg_x, party_avg_y)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
return
|
|
end
|
|
|
|
return
|
|
end
|
|
|
|
function actor_wt_front_1FB6E(actor)
|
|
--dgb("actor_wt_front_1FB6E()\n")
|
|
if (wt_num_monsters_near == 0 or wt_front_target_actor == nil) and actor.in_party == false then
|
|
subtract_movement_pts(actor, 5)
|
|
return 1
|
|
end
|
|
|
|
local player_loc = player_get_location()
|
|
|
|
local centre_x,centre_y,diff_x,diff_y,var_1E,var_24,var_14,var_12,var_20,var_1C,var_10,target_x,target_y,var_E
|
|
local actor_x = actor.x
|
|
local actor_y = actor.y
|
|
if actor.in_party == false then
|
|
centre_x = party_avg_x
|
|
centre_y = party_avg_y
|
|
diff_x = wt_front_target_actor.x - centre_x
|
|
diff_y = wt_front_target_actor.y - centre_y
|
|
else
|
|
centre_x = player_loc.x
|
|
centre_y = player_loc.y
|
|
diff_x = combat_avg_x - centre_x
|
|
diff_y = combat_avg_y - centre_y
|
|
end
|
|
|
|
--dgb("actor_wt_front_1FB6E() actor = ("..actor_x..","..actor_y..") centre = ("..centre_x..","..centre_y..") player = ("..player_loc.x..","..player_loc.y..")\n")
|
|
var_1E = (actor_x - centre_x) * diff_y - (actor_y - centre_y) * diff_x
|
|
if var_1E <= 0 then
|
|
var_24 = 0
|
|
else
|
|
var_24 = 1
|
|
end
|
|
|
|
if var_1E == 0 then
|
|
var_24 = math.random(0, 1)
|
|
end
|
|
|
|
if diff_y <= 0 then
|
|
var_14 = -1
|
|
else
|
|
var_14 = 1
|
|
end
|
|
|
|
if diff_x <= 0 then
|
|
var_12 = 1
|
|
else
|
|
var_12 = -1
|
|
end
|
|
|
|
if var_24 == 0 then
|
|
var_14 = -var_14
|
|
var_12 = -var_12
|
|
end
|
|
|
|
local tmp_actor
|
|
if actor.in_party == true then
|
|
tmp_actor = Actor.get_player_actor()
|
|
else
|
|
tmp_actor = wt_front_target_actor
|
|
end
|
|
|
|
--dgb("tmp_actor = "..tmp_actor.name.." at ("..tmp_actor.x..","..tmp_actor.y..")\n")
|
|
var_20 = (tmp_actor.x - centre_x) * diff_x + (tmp_actor.y - centre_y) * diff_y
|
|
if actor.in_party == true then
|
|
var_20 = var_20 + abs(diff_x) + abs(diff_y)
|
|
end
|
|
|
|
var_1C = diff_x * diff_x + diff_y * diff_y
|
|
if var_1C == 0 then
|
|
var_1C = 1
|
|
end
|
|
|
|
--dgb("getting target var_20 = "..var_20.." diff_x = "..diff_x.." diff_y = "..diff_y.." var_1C = "..var_1C.."\n")
|
|
target_x = math.floor((var_20 * diff_x) / var_1C) + centre_x
|
|
target_y = math.floor((var_20 * diff_y) / var_1C) + centre_y
|
|
|
|
unk_30A72 = 0
|
|
|
|
local chunk_x = player_loc.x - 16
|
|
chunk_x = chunk_x - (chunk_x % 8)
|
|
|
|
local chunk_y = player_loc.y - 16
|
|
chunk_y = chunk_y - (chunk_y % 8)
|
|
|
|
local found_actor = false
|
|
repeat
|
|
if target_x < chunk_x or chunk_x + 0x27 < target_x or target_y < chunk_y or chunk_y + 0x27 < target_y or (actor_x == target_x and actor_y == target_y) then
|
|
unk_30A72 = 1
|
|
--dgb("combat_front returned. too far away. actor=("..actor_x..","..actor_y..") target=("..target_x..","..target_y..") chunk=("..chunk_x..","..chunk_y..")\n")
|
|
return 1
|
|
end
|
|
|
|
if map_get_actor(target_x, target_y, player_loc.z) ~= nil then
|
|
found_actor = true
|
|
else
|
|
found_actor = false
|
|
end
|
|
|
|
if found_actor then
|
|
var_10 = (target_x + var_14 - centre_x) * diff_x + (target_y - centre_y) * diff_y
|
|
var_E = (target_x - centre_x) * diff_x + (target_y + var_12 - centre_y) * diff_y
|
|
|
|
if abs(var_10 - var_20) >= abs(var_E - var_20) then
|
|
target_y = target_y + var_12
|
|
else
|
|
target_x = target_x + var_14
|
|
end
|
|
end
|
|
until found_actor == false
|
|
|
|
|
|
local mpts = actor.mpts
|
|
if actor_move_towards_loc(actor, target_x, target_y) ~= 0 then
|
|
if actor.in_party == false or actor.x == target_x and actor.y == target_y then
|
|
return 0
|
|
end
|
|
|
|
if wt_num_monsters_near == 0 then
|
|
actor.mpts = mpts
|
|
end
|
|
|
|
if actor_move_towards_loc(actor, target_x, target_y) ~= 0 then
|
|
return 0
|
|
end
|
|
else
|
|
actor.mpts = mpts
|
|
end
|
|
|
|
actor_wt_attack(actor)
|
|
|
|
return 0
|
|
end
|
|
|
|
function actor_wt_rear(actor)
|
|
--dgb("actor_wt_rear()\n")
|
|
local var_C = 0
|
|
local player_loc = player_get_location()
|
|
local var_2,var_4,avg_y,avg_x,dx,ax,avg_x_diff, avg_y_diff
|
|
if actor.in_party == false then
|
|
|
|
if wt_num_monsters_near == 0 then subtract_movement_pts(actor, 5) return end
|
|
|
|
var_4 = wt_rear_min_monster
|
|
var_2 = wt_rear_max_monster
|
|
|
|
if var_4 == nil then var_4 = actor end
|
|
if var_2 == nil then var_2 = actor end
|
|
|
|
avg_x = combat_avg_x
|
|
avg_y = combat_avg_y
|
|
avg_x_diff = party_avg_x - combat_avg_x
|
|
avg_y_diff = party_avg_y - combat_avg_y
|
|
|
|
else
|
|
|
|
if wt_num_monsters_near == 0 then actor_move_towards_loc(actor, player_loc.x, player_loc.y) return end
|
|
|
|
var_4 = wt_rear_max_party
|
|
var_2 = wt_rear_min_party
|
|
avg_x = party_avg_x
|
|
avg_y = party_avg_y
|
|
avg_x_diff = combat_avg_x - party_avg_x
|
|
avg_y_diff = combat_avg_y - party_avg_y
|
|
end
|
|
|
|
local var_10 = 0x7fff
|
|
local align = actor.align
|
|
local i, var_12
|
|
for i=0,0xff do
|
|
local a = Actor.get(i)
|
|
|
|
if a.alive and a.wt == WT_FRONT and a.align == align then
|
|
|
|
var_12 = (a.x - avg_x) * avg_x_diff + (a.y - avg_y) * avg_y_diff
|
|
|
|
if var_12 < var_10 then var_10 = var_12 end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
var_12 = (actor.x - avg_x) * avg_x_diff + (actor.y - avg_y) * avg_y_diff
|
|
local mpts = actor.mpts
|
|
local var_C
|
|
if actor.in_party == false or actor_find_max_xy_distance(actor, player_loc.x, player_loc.y) <= 3 then
|
|
|
|
if var_12 < var_10 then
|
|
|
|
var_12 = (actor.x - avg_x) * avg_y_diff - (actor.y - avg_y) * avg_x_diff
|
|
|
|
dx = (var_4.x - avg_x) * avg_y_diff
|
|
if dx - (var_4.y - avg_y) * avg_x_diff >= var_12 then
|
|
|
|
dx = (var_2.x - avg_x) * avg_y_diff
|
|
ax = (var_2.y - avg_y) * avg_x_diff
|
|
if dx - ax <= var_12 then
|
|
|
|
var_C = 1
|
|
|
|
else
|
|
|
|
ax = (actor_move_towards_loc(actor, actor.x + avg_y_diff, actor.y - avg_x_diff) and -1 or 0) + 1
|
|
var_C = ax
|
|
end
|
|
|
|
else
|
|
|
|
ax = (actor_move_towards_loc(actor, actor.x - avg_y_diff, actor.y + avg_x_diff) and -1 or 0) + 1
|
|
var_C = ax
|
|
end
|
|
|
|
else
|
|
|
|
ax = (actor_move_towards_loc(actor, actor.x - avg_x_diff, actor.y - avg_y_diff) and -1 or 0) + 1
|
|
var_C = ax
|
|
end
|
|
|
|
else
|
|
|
|
ax = (actor_move_towards_loc(actor, player_loc.x, player_loc.y) and -1 or 0) + 1
|
|
var_C = ax
|
|
end
|
|
|
|
if var_C ~= 0 then
|
|
|
|
actor.mpts = mpts
|
|
actor_wt_attack(actor)
|
|
end
|
|
|
|
|
|
end
|
|
|
|
function actor_wt_flank(actor)
|
|
|
|
local player_loc = player_get_location()
|
|
local player_x = player_loc.x
|
|
local player_y = player_loc.y
|
|
|
|
local random = math.random
|
|
local abs = abs
|
|
|
|
if wt_num_monsters_near == 0 or actor.in_party == false and actor_find_max_xy_distance(actor, player_x, player_y) > 7 then
|
|
|
|
if actor.in_party == true and actor_find_max_xy_distance(actor, player_x, player_y) > 2 then
|
|
local mpts = actor.mpts
|
|
actor_move_towards_loc(actor, player_x, player_y)
|
|
actor.mpts = mpts
|
|
end
|
|
|
|
subtract_movement_pts(actor, 5)
|
|
return
|
|
end
|
|
|
|
local actor_align = actor.align
|
|
local actor_x = actor.x
|
|
local actor_y = actor.y
|
|
local tmp_x = combat_avg_x - party_avg_x
|
|
local tmp_y = combat_avg_y - party_avg_y
|
|
local var_20 = (actor_x - party_avg_x) * tmp_y - (actor_y - party_avg_y) * tmp_x
|
|
|
|
local var_1E, var_10, var_E
|
|
|
|
if var_20 <= 0 then
|
|
|
|
var_1E = 0
|
|
else
|
|
|
|
var_1E = 1
|
|
end
|
|
|
|
if var_20 == 0 then
|
|
|
|
var_1E = random(0, 1)
|
|
end
|
|
if var_1E == 0 then
|
|
|
|
var_10 = -tmp_y
|
|
var_E = tmp_x
|
|
var_20 = -var_20
|
|
else
|
|
|
|
var_10 = tmp_y
|
|
var_E = -tmp_x
|
|
end
|
|
|
|
local var_1A = -0x8000
|
|
local target_actor = nil
|
|
|
|
local i, tmp_actor
|
|
for i=1,0xff do
|
|
tmp_actor = Actor.get(i)
|
|
|
|
if tmp_actor ~= nil
|
|
and tmp_actor.alive == true
|
|
and tmp_actor.align ~= actor_align
|
|
and actor_ok_to_attack(actor, tmp_actor) == true
|
|
and (actor_align ~= ALIGNMENT_GOOD or alignment_is_evil(tmp_actor.align) == true)
|
|
and (actor_align ~= ALIGNMENT_EVIL or tmp_actor.align == ALIGNMENT_GOOD or tmp_actor.align == ALIGNMENT_CHAOTIC) then
|
|
|
|
local target_x = tmp_actor.x
|
|
local target_y = tmp_actor.y
|
|
|
|
if (tmp_actor.wt ~= WT_RETREAT and tmp_actor.wt ~= WT_FLEE and tmp_actor.wt ~= WT_MOUSE or player_x - 5 <= target_x and player_x + 5 >= target_x and player_y - 5 <= target_y and player_y + 5 >= target_y)
|
|
and (abs(target_x - player_x) <= 7 and abs(target_y - player_y) <= 7 or abs(target_x - actor_x) <= 5 and abs(target_y - actor_y) <= 5) then
|
|
|
|
local var_1C = (target_x - party_avg_x) * tmp_y - (target_y - party_avg_y) * tmp_x
|
|
if var_1E == 0 then
|
|
|
|
var_1C = -var_1C
|
|
end
|
|
|
|
if var_1C > var_1A then
|
|
|
|
var_1A = var_1C
|
|
target_actor = tmp_actor
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
if target_actor == nil then
|
|
actor_move_towards_player(actor)
|
|
return
|
|
end
|
|
|
|
g_obj = target_actor
|
|
tmp_x = target_actor.x
|
|
tmp_y = target_actor.y
|
|
|
|
local should_move_actor = false
|
|
local weapon_obj = actor_get_weapon(actor, target_actor)
|
|
local weapon_range = get_weapon_range(weapon_obj.obj_n)
|
|
local attack_range = Actor.get_range(actor, tmp_x, tmp_y)
|
|
|
|
if attack_range < 9 and attack_range <= weapon_range then
|
|
|
|
if map_can_reach_point(actor_x, actor_y, tmp_x, tmp_y, actor.z) == false then
|
|
if random(0, 1) == 0 then
|
|
tmp_x = target_actor.y - actor_y + actor_x
|
|
tmp_y = actor_y - target_actor.x - actor_x
|
|
else
|
|
tmp_x = actor_x - target_actor.y - actor_y
|
|
tmp_y = target_actor.x - actor_x + actor_y
|
|
end
|
|
should_move_actor = true
|
|
else
|
|
actor_attack(actor, tmp_x, tmp_y, actor.z, weapon_obj, target_actor)
|
|
subtract_movement_pts(actor, 10)
|
|
end
|
|
else
|
|
|
|
if var_10 <= 0 then
|
|
|
|
if var_10 < 0 then
|
|
|
|
tmp_x = tmp_x - 1
|
|
end
|
|
else
|
|
|
|
tmp_x = tmp_x + 1
|
|
end
|
|
if var_E <= 0 then
|
|
if var_E < 0 then
|
|
tmp_y = tmp_y - 1
|
|
end
|
|
else
|
|
tmp_y = tmp_y + 1
|
|
end
|
|
should_move_actor = true
|
|
end
|
|
|
|
if should_move_actor == true then
|
|
|
|
local mpts = actor.mpts
|
|
if actor_move_towards_loc(actor, tmp_x, tmp_y) == 0 then
|
|
|
|
actor.mpts = mpts
|
|
actor_wt_attack(actor)
|
|
end
|
|
end
|
|
|
|
return
|
|
end
|
|
|
|
|
|
function actor_wt_berserk(actor)
|
|
local target_actor = nil
|
|
local alignment = actor.align
|
|
local actor_x = actor.x
|
|
local actor_y = actor.y
|
|
local max_stats = 0
|
|
|
|
local i
|
|
for i=1,0xff do
|
|
local tmp_actor = Actor.get(i)
|
|
|
|
if tmp_actor ~= nil
|
|
and tmp_actor.alive == true
|
|
and tmp_actor.actor_num ~= actor.actor_num
|
|
and actor_find_max_xy_distance(tmp_actor, actor_x, actor_y) <= 8
|
|
and actor_ok_to_attack(actor, tmp_actor) == true
|
|
and (alignment ~= ALIGNMENT_GOOD or tmp_actor.align == ALIGNMENT_EVIL)
|
|
and (alignment ~= ALIGNMENT_EVIL or tmp_actor.align == ALIGNMENT_GOOD)
|
|
and (alignment ~= ALIGNMENT_CHAOTIC or (tmp_actor.align ~= ALIGNMENT_CHAOTIC and tmp_actor.align ~= ALIGNMENT_NEUTRAL)) then
|
|
local combined_stats = tmp_actor.str + tmp_actor.dex + tmp_actor.int
|
|
if combined_stats > max_stats then
|
|
max_stats = combined_stats
|
|
target_actor = tmp_actor
|
|
end
|
|
end
|
|
end
|
|
|
|
if target_actor == nil then
|
|
actor_wt_attack(actor)
|
|
subtract_movement_pts(actor, 5)
|
|
return
|
|
end
|
|
|
|
local target_x = target_actor.x
|
|
local target_y = target_actor.y
|
|
local weapon_obj = actor_get_weapon(actor, target_actor)
|
|
local weapon_range = get_weapon_range(weapon_obj.obj_n)
|
|
local attack_range = Actor.get_range(actor, target_x, target_y)
|
|
|
|
if attack_range < 9 and attack_range <= weapon_range then
|
|
|
|
--g_obj = target_actor
|
|
if map_can_reach_point(actor_x, actor_y, target_x, target_y, actor.z) == false then
|
|
|
|
if math.random(0, 1) == 0 then
|
|
target_x = target_actor.y - actor_y + actor_x
|
|
target_y = actor_y - target_actor.x - actor_x
|
|
else
|
|
target_x = actor_x - target_actor.y - actor_y
|
|
target_y = target_actor.x - actor_x + actor_y
|
|
end
|
|
else
|
|
actor_attack(actor, target_x, target_y, actor.z, weapon_obj, target_actor)
|
|
subtract_movement_pts(actor, 15)
|
|
return
|
|
end
|
|
|
|
end
|
|
|
|
local mpts = actor.mpts
|
|
if actor_move_towards_loc(actor, target_x, target_y) == 0 then
|
|
actor.mpts= mpts
|
|
actor_wt_attack(actor)
|
|
end
|
|
|
|
subtract_movement_pts(actor, 5)
|
|
return
|
|
end
|
|
|
|
function actor_wt_guard_arrest_player(actor)
|
|
if actor_catch_up_to_party(actor) == true then
|
|
caught_by_guard(actor)
|
|
end
|
|
end
|
|
|
|
function actor_wt_combat_tanglevine(actor)
|
|
local random = math.random
|
|
local di
|
|
local abs = abs
|
|
|
|
local target = actor_find_target(actor)
|
|
if target ~= nil then
|
|
|
|
local target_x = target.x
|
|
local target_y = target.y
|
|
local actor_x = actor.x
|
|
local actor_y = actor.y
|
|
if abs(target_x - actor_x) < 2 and abs(target_y - actor_y) < 2 and random(0, 1) ~= 0 then
|
|
|
|
actor_attack(actor, target_x, target_y, actor.z, actor, target)
|
|
subtract_movement_pts(actor, 10)
|
|
return
|
|
end
|
|
|
|
if abs(target_x - actor_x) < 5 and abs(target_y - actor_y) < 5 and random(0, 3) == 0 then
|
|
|
|
target_x = target_x - actor_x
|
|
target_y = target_y - actor_y
|
|
|
|
if abs(target_x) <= abs(target_y) then
|
|
|
|
di = (target_y <= 0) and DIR_NORTH or DIR_SOUTH
|
|
|
|
if move_tanglevine(actor, di) == 0 then
|
|
|
|
di = (target_x <= 0) and DIR_WEST or DIR_EAST
|
|
move_tanglevine(actor, di)
|
|
return
|
|
end
|
|
|
|
else
|
|
|
|
di = (target_x <= 0) and DIR_WEST or DIR_EAST
|
|
|
|
if move_tanglevine(actor, di) == 0 then
|
|
|
|
di = (target_y <= 0) and DIR_NORTH or DIR_SOUTH
|
|
move_tanglevine(actor, di)
|
|
return
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
if random(0, 3) == 0 then
|
|
|
|
di = random(0, 3) --random direction north south east west
|
|
if actor.direction == di then
|
|
|
|
di = direction_reverse(di)
|
|
end
|
|
|
|
move_tanglevine(actor, di)
|
|
|
|
else
|
|
actor.mpts = 0
|
|
end
|
|
|
|
return
|
|
end
|
|
|
|
|
|
function actor_wt_combat_stationary(actor)
|
|
local rand = math.random
|
|
local align = actor.align
|
|
if align == ALIGNMENT_NEUTRAL then
|
|
|
|
subtract_movement_pts(actor, 5)
|
|
return
|
|
end
|
|
|
|
local i
|
|
for i=1,0x10 do
|
|
|
|
local target_x = rand(0, 8) + actor.x - 4
|
|
local target_y = rand(0, 8) + actor.y - 4
|
|
-- local g_obj = sub_1D351(actor, target_x, target_y)
|
|
local target_actor = map_get_actor(target_x, target_y, actor.z)
|
|
|
|
if target_actor ~= nil and actor_ok_to_attack(actor, target_actor) == true and target_actor.alive == true and target_actor.align ~= align and target_actor.align ~= ALIGNMENT_NEUTRAL then
|
|
|
|
actor_attack(actor, target_x, target_y, actor.z, actor_get_weapon(actor, target_actor), target_actor)
|
|
subtract_movement_pts(actor, 10)
|
|
return
|
|
end
|
|
|
|
end
|
|
|
|
subtract_movement_pts(actor, 5)
|
|
|
|
return
|
|
end
|
|
|
|
function actor_wt_walk_straight(actor)
|
|
if math.random(0, 1) == 0 then subtract_movement_pts(actor, 5) return end
|
|
|
|
local wt = actor.wt
|
|
local sched = actor.sched_loc
|
|
local dir
|
|
|
|
if wt < WT_WALK_NORTH_SOUTH or actor.x ~= sched.x or actor.y ~= sched.y then
|
|
dir = actor.direction
|
|
else
|
|
if wt == WT_WALK_NORTH_SOUTH then dir = DIR_NORTH end
|
|
if wt == WT_WALK_EAST_WEST then dir = DIR_EAST end
|
|
if wt == WT_WALK_SOUTH_NORTH then dir = DIR_SOUTH end
|
|
if wt == WT_WALK_WEST_EAST then dir = DIR_WEST end
|
|
actor.direction = dir
|
|
end
|
|
|
|
local mpts = actor.mpts
|
|
|
|
if actor_move(actor, dir, 1) == 0 then
|
|
|
|
dir = direction_reverse(dir)
|
|
|
|
actor.mpts = mpts
|
|
actor_move(actor, dir, 1)
|
|
actor.direction = dir
|
|
end
|
|
|
|
end
|
|
|
|
function actor_wt_wander_around(actor)
|
|
local rand = math.random
|
|
if rand(0, 7) ~= 0 then subtract_movement_pts(actor, 5) return end
|
|
|
|
local random_wander_range = function ()
|
|
local i = 0
|
|
while rand(0, 1) ~= 0 do i = i + 1 end
|
|
if rand(0, 1) ~= 0 then i = -i end
|
|
return i
|
|
end
|
|
|
|
local abs=abs
|
|
local sched = actor.sched_loc
|
|
local sched_x_offset = actor.x - sched.x;
|
|
local sched_y_offset = actor.y - sched.y;
|
|
local direction
|
|
|
|
if abs(sched_y_offset) - abs(sched_x_offset) >= random_wander_range() then
|
|
direction = (random_wander_range() <= sched_y_offset) and DIR_NORTH or DIR_SOUTH
|
|
else
|
|
direction = (random_wander_range() <= sched_x_offset) and DIR_WEST or DIR_EAST
|
|
end
|
|
|
|
actor.direction = direction
|
|
actor_move(actor, direction, 1)
|
|
|
|
return
|
|
end
|
|
|
|
function actor_move_towards_player(actor)
|
|
local rand = math.random
|
|
if actor.wt ~= WT_STATIONARY then
|
|
if actor.in_party == true then
|
|
local player_loc = player_get_location()
|
|
local x,y = player_loc.x, player_loc.y
|
|
if actor.x ~= x and actor.y ~= y and rand(0, 3) == 0 then
|
|
actor_move_towards_loc(actor, x, y)
|
|
return
|
|
end
|
|
end
|
|
|
|
if rand(0, 7) == 0 then
|
|
actor_move(actor, rand(0, 3), 1)
|
|
return
|
|
end
|
|
end
|
|
subtract_movement_pts(actor, 5)
|
|
end
|
|
|
|
function actor_wt_attack(actor)
|
|
--dgb("actor_wt_attack()\n");
|
|
|
|
g_obj = actor_find_target(actor)
|
|
if g_obj ~= nil then
|
|
--dgb("target at ("..g_obj.x..","..g_obj.y..")\n")
|
|
end
|
|
|
|
local weapon_obj = actor_get_weapon(actor, g_obj)
|
|
|
|
if g_obj ~= nil then
|
|
|
|
local target_x = g_obj.x
|
|
local target_y = g_obj.y
|
|
local actor_x = actor.x
|
|
local actor_y = actor.y
|
|
local weapon_range = get_weapon_range(weapon_obj.obj_n)
|
|
|
|
if abs(target_x - actor_x) < 8 and abs(target_y - actor_y) < 8 and
|
|
Actor.get_range(actor, target_x, target_y) <= weapon_range then
|
|
|
|
if sub_1D59F(actor, target_x, target_y, weapon_range, 0) == true then
|
|
actor_attack(actor, g_obj.x, g_obj.y, g_obj.z, weapon_obj, g_obj)
|
|
subtract_movement_pts(actor, 10)
|
|
return
|
|
end
|
|
|
|
if math.random(0, 1) == 0 then
|
|
|
|
target_x = g_obj.y - actor_y + actor_x
|
|
target_y = actor_y - g_obj.x - actor_x
|
|
|
|
else
|
|
|
|
target_x = actor_x - g_obj.y - actor_y
|
|
target_y = g_obj.x - actor_x + actor_y
|
|
end
|
|
|
|
actor_move_towards_loc(actor, target_x, target_y)
|
|
return
|
|
end
|
|
|
|
if actor.wt ~= 3 then actor_move_towards_loc(actor, target_x, target_y) return end
|
|
|
|
subtract_movement_pts(actor, 5)
|
|
return
|
|
end
|
|
|
|
if actor.wt ~= 3 then actor_move_towards_player(actor) return end
|
|
|
|
|
|
subtract_movement_pts(actor, 5)
|
|
|
|
end
|
|
|
|
function actor_wt_timid(actor)
|
|
local player_loc = player_get_location()
|
|
if actor_find_max_xy_distance(actor, player_loc.x, player_loc.y) > 7 then
|
|
actor.mpts = 0
|
|
return
|
|
end
|
|
local target = actor_find_target(actor)
|
|
if target == nil then
|
|
actor_move_towards_player(actor)
|
|
return
|
|
end
|
|
local diff_x = target.x - actor.x
|
|
local diff_y = target.y - actor.y
|
|
local var_4
|
|
if actor.wt ~= WT_RETREAT then
|
|
var_4 = 3
|
|
else
|
|
var_4 = 8
|
|
end
|
|
|
|
if abs(diff_x) < var_4 and abs(diff_y) < var_4 then
|
|
local var_2 = actor.mpts
|
|
if actor_move_towards_loc(actor, actor.x - diff_x, actor.y - diff_y) == 0 then
|
|
--original logic -- actor.mpts = var_2
|
|
if actor.wt ~= WT_MOUSE and actor.wt ~= WT_FLEE then
|
|
actor.mpts = var_2 --moved here.
|
|
actor_wt_attack(actor)
|
|
end
|
|
end
|
|
else
|
|
if actor.align == ALIGNMENT_GOOD and actor.wt ~= WT_FLEE and actor.wt ~= WT_MOUSE then
|
|
actor_move_towards_loc(actor, party_avg_x, party_avg_y)
|
|
else
|
|
actor_move_towards_player(actor)
|
|
end
|
|
end
|
|
|
|
if actor.wt == WT_RETREAT then
|
|
if math.random(0, 3) == 0 then
|
|
if actor.level > actor.hp then
|
|
actor.hp = actor.hp + 1
|
|
end
|
|
|
|
if math.floor((actor.hp * 4) / actor.level) > 0 then
|
|
actor.wt = actor.combat_mode
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function actor_wt_like(actor)
|
|
local actor_x = actor.x
|
|
local actor_y = actor.y
|
|
local party_actor
|
|
local random = math.random
|
|
|
|
for party_actor in party_members() do
|
|
|
|
if abs(party_actor.x - actor_x) < 3 and abs(party_actor.y - actor_y) < 3 then
|
|
if random(0, 1) == 0 then
|
|
actor_move_towards_loc(actor, party_avg_x, party_avg_y)
|
|
return
|
|
end
|
|
|
|
break
|
|
end
|
|
end
|
|
|
|
if random(0, 1) == 0 then
|
|
subtract_movement_pts(actor, 5)
|
|
else
|
|
if random(0, 1) == 0 then
|
|
if random(0, 1) == 0 then
|
|
actor_y = actor_y - 10
|
|
else
|
|
actor_y = actor_y + 10
|
|
end
|
|
else
|
|
if random(0, 1) == 0 then
|
|
actor_x = actor_x - 10
|
|
else
|
|
actor_x = actor_x + 10
|
|
end
|
|
end
|
|
actor_move_towards_loc(actor, actor_x, actor_y)
|
|
end
|
|
|
|
return
|
|
end
|
|
|
|
function actor_wt_unfriendly(actor)
|
|
local actor_x = actor.x
|
|
local actor_y = actor.y
|
|
local party_actor
|
|
local random = math.random
|
|
|
|
for party_actor in party_members() do
|
|
if abs(party_actor.x - actor_x) < 3 and abs(party_actor.y - actor_y) < 3 then
|
|
|
|
if random(0, 7) == 0 then
|
|
actor.wt = WT_ASSAULT
|
|
actor_wt_attack(actor)
|
|
return
|
|
end
|
|
|
|
break
|
|
end
|
|
end
|
|
|
|
if random(0, 1) == 0 then
|
|
subtract_movement_pts(actor, 5)
|
|
else
|
|
if random(0, 1) == 0 then
|
|
if random(0, 1) == 0 then
|
|
actor_y = actor_y - 10
|
|
else
|
|
actor_y = actor_y + 10
|
|
end
|
|
else
|
|
if random(0, 1) == 0 then
|
|
actor_x = actor_x - 10
|
|
else
|
|
actor_x = actor_x + 10
|
|
end
|
|
end
|
|
actor_move_towards_loc(actor, actor_x, actor_y)
|
|
end
|
|
|
|
return
|
|
end
|
|
|
|
function actor_wt_walk_to_location(actor)
|
|
Actor.walk_path(actor)
|
|
if Actor.is_at_scheduled_location(actor) then
|
|
actor.wt = actor.sched_wt
|
|
if actor.wt == WT_SLEEP then
|
|
-- add extinguish light source code if actors with a light source actually go to sleep
|
|
actor_wt_sleep(actor)
|
|
end
|
|
end
|
|
|
|
subtract_movement_pts(actor, 5) --FIXME what's the movement cost for pathfinding?
|
|
end
|
|
|
|
function actor_wt_sleep(actor)
|
|
--dgb("actor_wt_sleep("..actor.name..") at "..actor.x..","..actor.y..","..actor.z.."\n")
|
|
local obj = map_get_obj(actor.x, actor.y, actor.z, 0xa3) --bed
|
|
if obj ~= nil then
|
|
if obj.frame_n == 1 or obj.frame_n == 5 then --horizontal bed
|
|
actor.obj_n = 0x92 -- person sleeping
|
|
actor.frame_n = 0
|
|
else
|
|
if obj.frame_n == 7 or obj.frame_n == 10 then --vertical bed
|
|
actor.obj_n = 0x92 -- person sleeping
|
|
actor.frame_n = 1
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function actor_wt_beg(actor)
|
|
local player_loc = player_get_location()
|
|
if actor.z == player_loc.z and abs(actor.x - player_loc.x) < 5 or abs(actor.y - player_loc.y) < 5 then
|
|
if actor_catch_up_to_party(actor) == true then
|
|
actor.wt = WT_WORK
|
|
Actor.talk(actor)
|
|
end
|
|
else
|
|
actor_wt_wander_around(actor)
|
|
end
|
|
end
|
|
|
|
function actor_wt_brawling(actor)
|
|
if math.random(0, 3) == 0 then
|
|
local target = actor_find_target(actor)
|
|
local player_loc = player_get_location()
|
|
if target ~= nil and actor_find_max_xy_distance(target, player_loc.x, player_loc.y) < 5 then
|
|
if actor_find_max_xy_distance(actor, target.x, target.y) < 2 then
|
|
hit_anim(target.x, target.y)
|
|
actor_move_towards_loc(actor, player_loc.x, player_loc.y)
|
|
else
|
|
actor_move_towards_loc(actor, target.x, target.y)
|
|
end
|
|
|
|
return
|
|
end
|
|
end
|
|
|
|
actor_wt_wander_around(actor)
|
|
end
|
|
|
|
wt_tbl = {
|
|
[WT_NOTHING] = {"WT_NOTHING", perform_worktype},
|
|
[WT_FRONT] = {"WT_FRONT", actor_wt_front},
|
|
[WT_REAR] = {"WT_REAR", actor_wt_rear},
|
|
[WT_FLANK] = {"WT_FLANK", actor_wt_flank},
|
|
[WT_BERSERK] = {"WT_BERSERK", actor_wt_berserk},
|
|
[WT_RETREAT] = {"WT_RETREAT", actor_wt_timid},
|
|
[WT_ASSAULT] = {"WT_ASSAULT", actor_wt_attack},
|
|
[WT_FLEE] = {"WT_FLEE", actor_wt_timid},
|
|
[WT_LIKE] = {"WT_LIKE", actor_wt_like},
|
|
[WT_UNFRIENDLY] = {"WT_UNFRIENDLY", actor_wt_unfriendly},
|
|
[WT_WANDER_NEAR_PLAYER] = {"WT_WANDER_NEAR_PLAYER", actor_move_towards_player},
|
|
[WT_TANGLE] = {"WT_TANGLE", actor_wt_combat_tanglevine},
|
|
[WT_STATIONARY] = {"WT_STATIONARY", actor_wt_combat_stationary},
|
|
[WT_GUARD_WALK_EAST_WEST] = {"WT_GUARD_WALK_EAST_WEST", actor_wt_walk_straight},
|
|
[WT_GUARD_WALK_NORTH_SOUTH] = {"WT_GUARD_WALK_NORTH_SOUTH", actor_wt_walk_straight},
|
|
--11
|
|
[WT_GUARD_ARREST_PLAYER] = {"WT_GUARD_ARREST_PLAYER", actor_wt_guard_arrest_player},
|
|
[WT_UNK_13] = {"WT_UNK_13", actor_wt_timid},
|
|
[WT_WALK_TO_LOCATION] = {"WT_WALK_TO_LOCATION", actor_wt_walk_to_location},
|
|
[WT_WALK_NORTH_SOUTH] = {"WT_WALK_NORTH_SOUTH", actor_wt_walk_straight},
|
|
[WT_WALK_EAST_WEST] = {"WT_WALK_EAST_WEST", actor_wt_walk_straight},
|
|
[WT_WALK_SOUTH_NORTH] = {"WT_WALK_SOUTH_NORTH", actor_wt_walk_straight},
|
|
[WT_WALK_WEST_EAST] = {"WT_WALK_WEST_EAST", actor_wt_walk_straight},
|
|
[WT_WANDER_AROUND] = {"WT_WANDER_AROUND", actor_move_towards_player},
|
|
[WT_WORK] = {"WT_WORK", actor_wt_wander_around},
|
|
[WT_UNK_94] = {"WT_UNK_94", actor_wt_wander_around},
|
|
[WT_BEG] = {"WT_BEG", actor_wt_beg},
|
|
[WT_ATTACK_PARTY] = {"WT_ATTACK_PARTY", actor_wt_attack},
|
|
[WT_BRAWLING] = {"WT_BRAWLING", actor_wt_brawling},
|
|
[WT_MOUSE] = {"WT_MOUSE", actor_wt_timid}
|
|
|
|
--[WT_] = {"WT_", actor_wt_rear}
|
|
}
|
|
|
|
function actor_ok_to_attack(actor, target_actor)
|
|
|
|
if target_actor.visible == false and (target_actor.in_party == false or actor.in_party == false) then return false end
|
|
|
|
if target_actor.z ~= actor.z then return false end
|
|
|
|
if target_actor.obj_n == 0x165 and target_actor.frame_n == 0 then return false end --corpser underground
|
|
|
|
if target_actor.corpser_flag == true then return false end
|
|
|
|
--FIXME need to check tileflag3 bit 4 is not set. The Ignore flag.
|
|
return true
|
|
|
|
end
|
|
|
|
function actor_find_target(actor)
|
|
|
|
local target_actor = nil
|
|
local align = actor.align
|
|
local actor_x = actor.x
|
|
local actor_y = actor.y
|
|
local var_2 = 0x7fff
|
|
local i
|
|
local player_loc = player_get_location()
|
|
local player_x = player_loc.x
|
|
local player_y = player_loc.y
|
|
|
|
for i=0,0xff do
|
|
|
|
local tmp_actor = Actor.get(i)
|
|
|
|
if tmp_actor.obj_n ~= 0 and tmp_actor.alive == true and tmp_actor.actor_num ~= actor.actor_num and actor_ok_to_attack(actor, tmp_actor) == true then
|
|
|
|
if actor.wt == WT_FLEE or
|
|
actor.wt == WT_MOUSE or
|
|
actor.wt == WT_UNK_13 or
|
|
actor.wt == WT_RETREAT or
|
|
actor.wt == WT_BRAWLING or
|
|
(align ~= ALIGNMENT_NEUTRAL or actor.wt == WT_ATTACK_PARTY and tmp_actor.align == ALIGNMENT_GOOD) and
|
|
(align ~= ALIGNMENT_CHAOTIC or tmp_actor.align ~= ALIGNMENT_CHAOTIC) and
|
|
tmp_actor.align ~= ALIGNMENT_NEUTRAL and
|
|
(align ~= ALIGNMENT_GOOD or alignment_is_evil(tmp_actor.align) == true) and
|
|
(align ~= ALIGNMENT_EVIL or tmp_actor.align == ALIGNMENT_GOOD or tmp_actor.align == ALIGNMENT_CHAOTIC) then
|
|
|
|
local target_x = tmp_actor.x
|
|
local target_y = tmp_actor.y
|
|
|
|
if actor_find_max_xy_distance(actor, target_x, target_y) <= 8 and (tmp_actor.wt ~= WT_RETREAT or abs(target_x - player_x) <= 5 and abs(target_y - player_y) <= 5) then
|
|
|
|
local var_6 = (target_x - actor_x)^2 + (target_y - actor_y)^2
|
|
if var_6 < var_2 or var_6 == var_2 and math.random(0, 1) ~= 0 then
|
|
|
|
var_2 = var_6
|
|
target_actor = tmp_actor
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
return target_actor
|
|
end
|
|
|
|
--FIXME this is a line of sight check for combat.
|
|
function sub_1D59F(actor, target_x, target_y, weapon_obj)
|
|
return map_can_reach_point(actor.x, actor.y, target_x, target_y, actor.z)
|
|
end
|
|
|
|
|
|
|
|
function perform_worktype(actor)
|
|
|
|
if g_time_stopped == true then
|
|
actor.mpts = 0
|
|
return
|
|
end
|
|
|
|
if wt_tbl[actor.wt] == nil then
|
|
subtract_movement_pts(actor, 5)
|
|
return
|
|
end
|
|
|
|
--dgb("wt = "..wt_tbl[actor.wt][1].."\n")
|
|
|
|
if actor.mpts > 0 then
|
|
local func = wt_tbl[actor.wt][2]
|
|
func(actor)
|
|
end
|
|
|
|
if actor.mpts == 0 then subtract_movement_pts(actor, 0xa) end
|
|
|
|
end
|
|
|
|
function spell_put_actor_to_sleep(attacker, foe)
|
|
|
|
--dgb("spell_put_actor_to_sleep("..attacker.name..",foe)\n")
|
|
|
|
local actor_base = actor_tbl[foe.obj_n]
|
|
if actor_base == nil or actor_base[21] == 0 then -- 21 is immune to sleep
|
|
if actor_int_check(foe, attacker) == false then
|
|
hit_anim(foe.x, foe.y)
|
|
actor_put_to_sleep(foe)
|
|
return 0xfe
|
|
else
|
|
return 1
|
|
end
|
|
end
|
|
|
|
return 2
|
|
end
|
|
|
|
function spell_poison_actor(attacker, foe)
|
|
local actor_base = actor_tbl[foe.obj_n]
|
|
if actor_base == nil or actor_base[19] == 1 or foe.actor_num == 0 then return 2 end --immune to poison
|
|
|
|
if math.floor((math.floor(actor_str_adj(foe) / 2) + 0x1e - actor_int_adj(attacker)) / 2) <= math.random(1, 0x1e) then
|
|
foe.poisoned = true
|
|
hit_anim(foe.x, foe.y)
|
|
return -1
|
|
end
|
|
|
|
return 1
|
|
end
|
|
|
|
function spell_take_fire_dmg(attacker, foe)
|
|
local actor_base = actor_tbl[foe.obj_n]
|
|
if actor_base == nil or actor_base[18] == 1 then return end --immune to magic
|
|
|
|
local dmg = math.random(1, 0x14)
|
|
|
|
if actor_base == nil or actor_base[17] == 1 then dmg = dmg * 2 end --double dmg from fire
|
|
|
|
local exp = actor_hit(foe, dmg)
|
|
if exp ~= 0 then
|
|
attacker.exp = attacker.exp + exp
|
|
end
|
|
|
|
actor_yell_for_help(attacker, foe, 1)
|
|
actor_hit_msg(foe)
|
|
end
|
|
|
|
function spell_charm_actor(attacker, foe)
|
|
if actor_int_check(foe, attacker) == true then return false end
|
|
|
|
if foe.charmed == true then
|
|
actor_remove_charm(foe)
|
|
else
|
|
foe.charmed = true
|
|
foe.old_align = foe.align
|
|
foe.align = attacker.align
|
|
hit_anim(foe.x, foe.y)
|
|
print("\n"..foe.name.." is charmed.\n")
|
|
if foe.in_party == true then
|
|
party_update_leader()
|
|
end
|
|
end
|
|
|
|
return true
|
|
end
|
|
|
|
function spell_kill_actor(attacker, foe)
|
|
local actor_base = actor_tbl[foe.obj_n]
|
|
if actor_base ~= nil and actor_base[20] == 1 then return 2 end --immune to corp spells
|
|
|
|
if actor_int_check(foe, attacker) == true then return 1 end
|
|
|
|
local exp = actor_hit(foe, foe.hp)
|
|
if exp ~= 0 then
|
|
attacker.exp = attacker.exp + exp
|
|
end
|
|
|
|
actor_yell_for_help(attacker, foe, 1)
|
|
actor_hit_msg(foe)
|
|
|
|
return -1
|
|
end
|
|
|
|
function spell_hit_actor(attacker, foe, spell_num)
|
|
|
|
if actor_int_check(foe, attacker) == true then return false end
|
|
local random = math.random
|
|
local dmg = 0
|
|
|
|
if spell_num == 5 then
|
|
dmg = random(1, 0xa)
|
|
elseif spell_num == 0x62 then
|
|
dmg = random(1, 0x1e)
|
|
elseif spell_num == 0x32 then
|
|
dmg = foe.hp - 1
|
|
end
|
|
|
|
print("\n")
|
|
|
|
local exp = actor_hit(foe, dmg)
|
|
if exp ~= 0 then
|
|
attacker.exp = attacker.exp + exp
|
|
end
|
|
|
|
actor_hit_msg(foe)
|
|
|
|
actor_yell_for_help(attacker, foe, 1)
|
|
|
|
return true
|
|
end
|
|
|
|
function actor_use_effect(actor, effect)
|
|
local random = math.random
|
|
local effect_type = random(0, 3)
|
|
Obj.removeFromEngine(effect) -- moved here so it won't be seen in chest
|
|
if effect_type == 0 then
|
|
print("Acid!\n")
|
|
actor_hit(actor, random(1, 0x14))
|
|
|
|
elseif effect_type == 1 then
|
|
print("Poison!\n")
|
|
actor.poisoned = true
|
|
hit_anim(actor.x, actor.y)
|
|
|
|
elseif effect_type == 2 then
|
|
print("Bomb!\n")
|
|
local hit_items = explosion(0x17e, actor.x, actor.y)
|
|
|
|
for k,v in pairs(hit_items) do
|
|
if v.luatype == "actor" then
|
|
actor_hit(v, random(1, 0x14))
|
|
end
|
|
end
|
|
|
|
elseif effect_type == 3 then
|
|
print("Gas!\n")
|
|
local hit_items = explosion(0x17c, actor.x, actor.y)
|
|
|
|
for k,v in pairs(hit_items) do
|
|
if v.luatype == "actor" then
|
|
v.poisoned = true
|
|
hit_anim(v.x, v.y)
|
|
end
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
function actor_resurrect(actor)
|
|
local karma = player_get_karma()
|
|
if karma < 98 then
|
|
actor.exp = math.floor((actor.exp * karma) / 100)
|
|
end
|
|
end
|
|
|
|
function get_LB_to_throne()
|
|
local cur_hour = clock_get_hour()
|
|
-- LB is on throne at 8-12 and 14-18
|
|
while cur_hour < 8 or cur_hour > 17 or (cur_hour > 11 and cur_hour < 14) do
|
|
advance_time(60)
|
|
cur_hour = clock_get_hour()
|
|
end
|
|
end
|
|
|
|
function actor_avatar_death()
|
|
|
|
--FIXME the hit tile is displayed constantly while the death tune is playing.
|
|
g_avatar_died = false -- before get_LB_to_throne()
|
|
local avatar = Actor.get(1)
|
|
if avatar.obj_n == 431 then --horse with rider
|
|
Actor.use(avatar) --dismount from horse
|
|
end
|
|
avatar.asleep = true --we do this so it looks like the avatar is dead.
|
|
print("\nAn unending darkness engulfs thee...\n\n")
|
|
play_sfx(SFX_AVATAR_DEATH, true)
|
|
fade_out()
|
|
print("A voice in the darkness intones, \"KAL LOR!\"\n")
|
|
play_sfx(SFX_KAL_LOR, true)
|
|
avatar.asleep = false
|
|
party_dismount_from_horses();
|
|
if g_armageddon == false then
|
|
party_resurrect_dead_members()
|
|
end
|
|
|
|
--unready inventory objects.
|
|
for obj in actor_inventory(avatar) do
|
|
if obj.readied and obj.obj_n ~= 76 then -- don't display message for amulet of submission
|
|
Actor.inv_unready_obj(avatar, obj)
|
|
end
|
|
end
|
|
party_heal() -- need to heal before player_move
|
|
party_update_leader()
|
|
player_move(0x133, 0x160, 0, true)
|
|
party_exit_vehicle(0x133, 0x160, 0)
|
|
get_LB_to_throne()
|
|
|
|
for i=0,0xff do
|
|
local actor = Actor.get(i)
|
|
actor.mpts = 0
|
|
if actor.temp == false and actor.wt == WT_ATTACK_PARTY then
|
|
actor.wt = WT_WALK_TO_LOCATION
|
|
end
|
|
end
|
|
avatar.mpts=1
|
|
|
|
actor_resurrect(avatar)
|
|
party_set_combat_mode(false)
|
|
party_set_party_mode()
|
|
fade_in()
|
|
end
|
|
|
|
--io.stderr:write("actor.lua loaded\n")
|