ULTIMA8: Enable crusader firing from animation flags

This commit is contained in:
Matthew Duggan 2020-12-18 15:11:10 +09:00
parent fe32fcf596
commit 280c103bc5
4 changed files with 55 additions and 1 deletions

View File

@ -267,6 +267,8 @@ void ActorAnimProcess::run() {
doSpecial();
} else if (curframe->_flags & AnimFrame::AFF_HURTY && GAME_IS_CRUSADER) {
a->tookHitCru();
} else if (curframe->is_cruattack() && GAME_IS_CRUSADER) {
doFireWeaponCru(a, curframe);
}
}
@ -497,6 +499,30 @@ void ActorAnimProcess::doSpecial() {
}
void ActorAnimProcess::doFireWeaponCru(Actor *a, const AnimFrame *f) {
assert(a);
assert(f);
if (!f->is_cruattack())
return;
// TODO: there is some special casing in the game for larger weapons here..
const Item *wpn = getItem(a->getActiveWeapon());
if (!wpn)
return;
const ShapeInfo *wpninfo = wpn->getShapeInfo();
if (!wpninfo || !wpninfo->_weaponInfo)
return;
a->fireWeapon(f->cru_attackx(), f->cru_attacky(), f->cru_attackz(),
dir_current, wpninfo->_weaponInfo->_damageType, 1);
AudioProcess *audioproc = AudioProcess::get_instance();
if (audioproc)
audioproc->playSFX(wpninfo->_weaponInfo->_sound, 0x80, a->getObjId(), 0, false);
}
void ActorAnimProcess::doHitSpecial(Item *hit) {
Actor *a = getActor(_itemNum);

View File

@ -32,6 +32,7 @@ namespace Ultima8 {
class Actor;
class AnimAction;
class AnimFrame;
class AnimationTracker;
class Item;
@ -69,6 +70,9 @@ protected:
//! perform special action when hitting an opponent
void doHitSpecial(Item *hit);
//! Fire weapon
void doFireWeaponCru(Actor *actor, const AnimFrame *frame);
Animation::Sequence _action;
Direction _dir;
uint32 _steps;

View File

@ -69,6 +69,28 @@ struct AnimFrame {
inline int attack_range() const {
return ((_flags >> 2) & 0x07);
}
// Note: The next 3 functions each have a 4-bit
// signed value to unpack from the flags.
inline int cru_attackx() const {
uint32 rawx = (_flags & 0x00000780) << 5;
int16 signedx = static_cast<int16>(rawx) >> 12;
return signedx * 16;
}
inline int cru_attacky() const {
uint32 rawy = (_flags & 0x00F00000) >> 16;
return static_cast<int8>(rawy);
}
inline int cru_attackz() const {
uint32 rawz = (_flags & 0x0F000000) >> 20;
return static_cast<int8>(rawz) / 2;
}
inline bool is_cruattack() const {
return (cru_attackx() || cru_attacky() || cru_attackz());
}
};
class AnimAction {

View File

@ -1176,7 +1176,9 @@ uint16 Item::fireWeapon(int32 x, int32 y, int32 z, Direction dir, int firetype,
int damage = firetypedat->getRandomDamage();
const Item *blocker = nullptr;
bool isvalid = currentmap->isValidPosition(ix, iy, iz, BULLET_SPLASH_SHAPE, 0, nullptr, nullptr, &blocker);
// CHECKME: the original doesn't exclude the source like this,
// but it seems obvious we have to or NPCs shoot themselves?
bool isvalid = currentmap->isValidPosition(ix, iy, iz, BULLET_SPLASH_SHAPE, _objId, nullptr, nullptr, &blocker);
if (!isvalid && blocker) {
Item *block = getItem(blocker->getObjId());
Point3 blockpt;