Skip to content

Commit

Permalink
Auto melee (fixes #742 )
Browse files Browse the repository at this point in the history
  • Loading branch information
cxong committed Nov 1, 2022
1 parent 0f23341 commit e7a4917
Show file tree
Hide file tree
Showing 16 changed files with 250 additions and 139 deletions.
3 changes: 2 additions & 1 deletion data/.wolf3d/SD2data.cdogscpn/guns.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
"Lock": 30,
"Sound": "",
"SwitchSound": "knife_switch",
"CanShoot": false
"CanShoot": false,
"Auto": true
},
{
"Pic": "pistol",
Expand Down
3 changes: 2 additions & 1 deletion data/.wolf3d/SD3data.cdogscpn/guns.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
"Lock": 30,
"Sound": "",
"SwitchSound": "knife_switch",
"CanShoot": false
"CanShoot": false,
"Auto": true
},
{
"Pic": "pistol",
Expand Down
3 changes: 2 additions & 1 deletion data/.wolf3d/common.cdogscpn/guns.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
"Lock": 30,
"Sound": "",
"SwitchSound": "knife_switch",
"CanShoot": false
"CanShoot": false,
"Auto": true
},
{
"Pic": "pistol",
Expand Down
3 changes: 2 additions & 1 deletion dogfights/dwango5_map01.cdogscpn/guns.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@
"Cost": 0,
"Sound": "",
"SoundLockLength": 50,
"CanShoot": false
"CanShoot": false,
"Auto": true
},
{
"Name": "Plasma gun",
Expand Down
3 changes: 2 additions & 1 deletion dogfights/map07.cdogscpn/guns.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@
"Cost": 0,
"Sound": "",
"SoundLockLength": 50,
"CanShoot": false
"CanShoot": false,
"Auto": true
},
{
"Name": "Plasma gun",
Expand Down
16 changes: 15 additions & 1 deletion missions/doom.cdogscpn/guns.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
{
"Version": 2,
"Guns": [
{
"Pic": "",
"Icon": "fist",
"Name": "Fists",
"Bullet": "fist",
"Cost": 0,
"Lock": 30,
"Sound": "",
"SwitchSound": "knuckles",
"CanShoot": false,
"CanDrop": false,
"Auto": true
},
{
"Pic": "chainsaw",
"Icon": "chainsaw",
Expand All @@ -11,7 +24,8 @@
"Lock": 0,
"Sound": "",
"SoundLockLength": 50,
"CanShoot": false
"CanShoot": false,
"Auto": true
},
{
"Pic": "pistol",
Expand Down
3 changes: 2 additions & 1 deletion src/autosave.c
Original file line number Diff line number Diff line change
Expand Up @@ -457,9 +457,10 @@ void PlayerSavesApply(const CArray *playerSaves, const bool weaponPersist)
{
if (ps->Guns[j] != NULL)
{
p->guns[j] = StrWeaponClass(ps->Guns[j]);
PlayerAddWeapon(p, StrWeaponClass(ps->Guns[j]));
}
}
PlayerAddMinimalWeapons(p);
CArrayCopy(&p->ammo, &ps->ammo);
}
if (ps->Lives > 0)
Expand Down
171 changes: 118 additions & 53 deletions src/cdogs/actors.c
Original file line number Diff line number Diff line change
Expand Up @@ -324,66 +324,87 @@ bool TryMoveActor(TActor *actor, struct vec2 pos)
IsPVP(gCampaign.Entry.Mode), false};
Thing *target = OverlapGetFirstItem(
&actor->thing, pos, actor->thing.size, actor->thing.Vel, params);
if (target)
if (target && actor->health > 0)
{
Weapon *gun = ACTOR_GET_WEAPON(actor);
const TObject *object = target->kind == KIND_OBJECT
? CArrayGet(&gObjs, target->id)
: NULL;
const int barrel = ActorGetCanFireBarrel(actor, gun);
// Check for melee damage if we are the owner of the actor
const bool checkMelee =
(!gCampaign.IsClient && actor->PlayerUID < 0) ||
ActorIsLocalPlayer(actor->uid);
// TODO: support melee weapons on multi guns
const BulletClass *b = WeaponClassGetBullet(gun->Gun, barrel);
if (checkMelee && barrel >= 0 && !WeaponClassCanShoot(gun->Gun) &&
actor->health > 0 && b &&
(!object ||
(((b->Hit.Object.Hit && target->kind == KIND_OBJECT) ||
(b->Hit.Flesh.Hit && target->kind == KIND_CHARACTER)) &&
!ObjIsDangerous(object))))
if ((object && !ObjIsDangerous(object)) ||
target->kind == KIND_CHARACTER)
{
if (CanHit(b, actor->flags, actor->uid, target))
// We are running into an object or actor
// If we have an auto-melee weapon, switch to it
const WeaponClass *meleeGun = actor->guns[MELEE_SLOT].Gun;
if (actor->gunIndex != MELEE_SLOT && meleeGun &&
meleeGun->Type == GUNTYPE_MELEE && meleeGun->u.Normal.Auto)
{
// Tell the server that we want to melee something
GameEvent e = GameEventNew(GAME_EVENT_ACTOR_MELEE);
e.u.Melee.UID = actor->uid;
strcpy(e.u.Melee.BulletClass, b->Name);
e.u.Melee.TargetKind = target->kind;
switch (target->kind)
{
case KIND_CHARACTER:
e.u.Melee.TargetUID =
((const TActor *)CArrayGet(&gActors, target->id))
->uid;
e.u.Melee.HitType = HIT_FLESH;
break;
case KIND_OBJECT:
e.u.Melee.TargetUID =
((const TObject *)CArrayGet(&gObjs, target->id))
->uid;
e.u.Melee.HitType = HIT_OBJECT;
break;
default:
CASSERT(false, "cannot damage target kind");
break;
}
if (gun->barrels[barrel].soundLock > 0)
{
e.u.Melee.HitType = (int)HIT_NONE;
}
GameEvent e = GameEventNew(GAME_EVENT_ACTOR_SWITCH_GUN);
e.u.ActorSwitchGun.UID = actor->uid;
e.u.ActorSwitchGun.GunIdx = MELEE_SLOT;
GameEventsEnqueue(&gGameEvents, e);
WeaponBarrelOnFire(gun, barrel);

// Only set grimace when counter 0 so that the actor
// alternates their grimace
if (actor->grimaceCounter == 0)
}
else
{
Weapon *gun = ACTOR_GET_WEAPON(actor);
const int barrel = ActorGetCanFireBarrel(actor, gun);
// Check for melee damage if we are the owner of the actor
const bool checkMelee =
(!gCampaign.IsClient && actor->PlayerUID < 0) ||
ActorIsLocalPlayer(actor->uid);
// TODO: support melee weapons on multi guns
const BulletClass *b =
WeaponClassGetBullet(gun->Gun, barrel);
if (checkMelee && barrel >= 0 &&
!WeaponClassCanShoot(gun->Gun) && b &&
(!object || (((b->Hit.Object.Hit &&
target->kind == KIND_OBJECT) ||
(b->Hit.Flesh.Hit &&
target->kind == KIND_CHARACTER)))))
{
actor->grimaceCounter = GRIMACE_MELEE_TICKS;
if (CanHit(b, actor->flags, actor->uid, target))
{
// Tell the server that we want to melee something
GameEvent e = GameEventNew(GAME_EVENT_ACTOR_MELEE);
e.u.Melee.UID = actor->uid;
strcpy(e.u.Melee.BulletClass, b->Name);
e.u.Melee.TargetKind = target->kind;
switch (target->kind)
{
case KIND_CHARACTER:
e.u.Melee.TargetUID =
((const TActor *)CArrayGet(
&gActors, target->id))
->uid;
e.u.Melee.HitType = HIT_FLESH;
break;
case KIND_OBJECT:
e.u.Melee.TargetUID =
((const TObject *)CArrayGet(
&gObjs, target->id))
->uid;
e.u.Melee.HitType = HIT_OBJECT;
break;
default:
CASSERT(false, "cannot damage target kind");
break;
}
if (gun->barrels[barrel].soundLock > 0)
{
e.u.Melee.HitType = (int)HIT_NONE;
}
GameEventsEnqueue(&gGameEvents, e);
WeaponBarrelOnFire(gun, barrel);

// Only set grimace when counter 0 so that the
// actor alternates their grimace
if (actor->grimaceCounter == 0)
{
actor->grimaceCounter = GRIMACE_MELEE_TICKS;
}
}
return false;
}
}
return false;
}

const struct vec2 yPos = svec2(actor->Pos.x, pos.y);
Expand Down Expand Up @@ -868,6 +889,17 @@ static void FireWeapon(TActor *a, Weapon *w)
{
return;
}
// If currently equipping an auto-melee weapon,
// and if possible, switch to the last gun
if (w->Gun->Type == GUNTYPE_MELEE && w->Gun->u.Normal.Auto &&
a->guns[a->lastGunIdx].Gun != NULL)
{
GameEvent e = GameEventNew(GAME_EVENT_ACTOR_SWITCH_GUN);
e.u.ActorSwitchGun.UID = a->uid;
e.u.ActorSwitchGun.GunIdx = a->lastGunIdx;
GameEventsEnqueue(&gGameEvents, e);
return;
}
const int barrel = ActorGetCanFireBarrel(a, w);
if (barrel == -1)
{
Expand Down Expand Up @@ -1813,6 +1845,37 @@ int ActorGetCanFireBarrel(const TActor *a, const Weapon *w)
}
return barrel;
}
static bool CanSwitchToWeapon(const TActor *a, const int slot)
{
const WeaponClass *wc = a->guns[slot].Gun;
if (wc == NULL)
{
return false;
}
// Don't cycle to auto-melee or default melee unless there are no guns with ammo
if (slot == MELEE_SLOT && wc->u.Normal.Auto)
{
for (int i = 0; i < MELEE_SLOT; i++)
{
const WeaponClass *wc2 = a->guns[i].Gun;
if (wc2 != NULL)
{
if (!gCampaign.Setting.Ammo)
{
return false;
}
for (int j = 0; j < WeaponClassNumBarrels(wc2); j++)
{
if (ActorWeaponGetAmmo(a, wc2, j) != 0)
{
return false;
}
}
}
}
}
return true;
}
bool ActorTrySwitchWeapon(const TActor *a, const bool allGuns)
{
// Find the next weapon to switch to
Expand All @@ -1824,9 +1887,7 @@ bool ActorTrySwitchWeapon(const TActor *a, const bool allGuns)
do
{
weaponIndex = (weaponIndex + 1) % switchCount;
} while (a->guns[weaponIndex].Gun ==
NULL); // TODO: don't cycle to auto-melee or default melee unless
// it's the only gun
} while (!CanSwitchToWeapon(a, weaponIndex));
if (weaponIndex == startIndex)
{
// No other weapon to switch to
Expand All @@ -1845,6 +1906,10 @@ void ActorSwitchGun(const NActorSwitchGun sg)
if (a == NULL || !a->isInUse)
return;
a->gunIndex = sg.GunIdx;
if (sg.GunIdx < MELEE_SLOT)
{
a->lastGunIdx = sg.GunIdx;
}
const WeaponClass *gun = ACTOR_GET_WEAPON(a)->Gun;
SoundPlayAt(&gSoundDevice, gun->SwitchSound, a->thing.Pos);
ActorSetChatter(a, gun->name, CHATTER_SWITCH_GUN);
Expand Down
1 change: 1 addition & 0 deletions src/cdogs/actors.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ typedef struct Actor
Weapon guns[MAX_WEAPONS];
CArray ammo; // of int
int gunIndex;
int lastGunIdx;

int health;
// A counter for player death
Expand Down
13 changes: 0 additions & 13 deletions src/cdogs/ai_coop.c
Original file line number Diff line number Diff line change
Expand Up @@ -850,7 +850,6 @@ static int GotoObjective(TActor *actor, const float objDistance2)
return cmd;
}

static bool PlayerHasWeapon(const PlayerData *p, const WeaponClass *wc);
void AICoopSelectWeapons(
PlayerData *p, const int player, const CArray *weapons)
{
Expand Down Expand Up @@ -897,18 +896,6 @@ void AICoopSelectWeapons(
}
}
}
static bool PlayerHasWeapon(const PlayerData *p, const WeaponClass *wc)
{
for (int i = 0; i < MAX_WEAPONS; i++)
{
const WeaponClass *wc2 = p->guns[i];
if (wc == wc2)
{
return true;
}
}
return false;
}

void AICoopOnPickupGun(TActor *a, const int gunId)
{
Expand Down
Loading

0 comments on commit e7a4917

Please sign in to comment.