Skip to content

Commit

Permalink
Track bullet source weapon and calculate fav weapon, acc in high scores
Browse files Browse the repository at this point in the history
  • Loading branch information
cxong committed Mar 5, 2025
1 parent 2da35d5 commit 3eba2e8
Show file tree
Hide file tree
Showing 21 changed files with 589 additions and 217 deletions.
2 changes: 2 additions & 0 deletions src/cdogs/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ set(CDOGS_SOURCES
vector.c
weapon.c
weapon_class.c
weapon_usage.c
window_context.c
XGetopt.c
yajl_utils.c)
Expand Down Expand Up @@ -225,6 +226,7 @@ set(CDOGS_HEADERS
vector.h
weapon.h
weapon_class.h
weapon_usage.h
window_context.h
XGetopt.h
yajl_utils.h)
Expand Down
1 change: 1 addition & 0 deletions src/cdogs/actor_fire.c
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ void OnGunFire(const NGunFire gf, SoundDevice *sd)
wc->u.Normal.ElevationLow, wc->u.Normal.ElevationHigh);
ab.u.AddBullet.Flags = gf.Flags;
ab.u.AddBullet.ActorUID = gf.ActorUID;
strcpy(ab.u.AddBullet.Gun, wc->name);

CA_FOREACH(const BulletClass *, bc, wc->u.Normal.Bullets)
ab.u.AddBullet.UID = MobObjsObjsGetNextUID();
Expand Down
35 changes: 21 additions & 14 deletions src/cdogs/actors.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
This file incorporates work covered by the following copyright and
permission notice:
Copyright (c) 2013-2024 Cong Xu
Copyright (c) 2013-2025 Cong Xu
All rights reserved.
Redistribution and use in source and binary forms, with or without
Expand Down Expand Up @@ -143,7 +143,8 @@ void UpdateActorState(TActor *actor, int ticks)
actor->petrified = MAX(0, actor->petrified - ticks);
actor->confused = MAX(0, actor->confused - ticks);

// Reset accumulated damage if FPS_FRAMELIMIT passed since taking damage
// Reset accumulated damage if FPS_FRAMELIMIT passed since taking
// damage
actor->damageCooldownTicks += ticks;
if (actor->accumulatedDamage)
{
Expand Down Expand Up @@ -714,8 +715,8 @@ static void CheckRescue(const TActor *a)
if (a->PlayerUID < 0)
return;

// Check an area slightly bigger than the actor's size for rescue
// objectives
// Check an area slightly bigger than the actor's size for rescue
// objectives
#define RESCUE_CHECK_PAD 2
const CollisionParams params = {
THING_IMPASSABLE, CalcCollisionTeam(true, a),
Expand Down Expand Up @@ -2181,16 +2182,14 @@ static void ActorTakeSpecialDamage(
}
}

static void ActorTakeHit(
TActor *actor, const int flags, const int sourceUID,
const special_damage_e damage, const int specialTicks);
static void ActorTakeHit(TActor *actor, const NThingDamage d);
void ActorHit(const NThingDamage d)
{
TActor *a = ActorGetByUID(d.UID);
if (!a->isInUse)
return;

ActorTakeHit(a, d.Flags, d.SourceActorUID, d.Special, d.SpecialTicks);
ActorTakeHit(a, d);
if (d.Power > 0)
{
DamageActor(a, d.Power, d.SourceActorUID);
Expand Down Expand Up @@ -2245,23 +2244,31 @@ void ActorHit(const NThingDamage d)
}
}

static void ActorTakeHit(
TActor *actor, const int flags, const int sourceUID,
const special_damage_e damage, const int specialTicks)
static void ActorTakeHit(TActor *actor, const NThingDamage d)
{
// Wake up if this is an AI
if (!gCampaign.IsClient)
{
AIWake(actor, 1);
}
const TActor *source = ActorGetByUID(sourceUID);
const TActor *source = ActorGetByUID(d.SourceActorUID);
const int playerUID = source != NULL ? source->PlayerUID : -1;
if (ActorIsInvulnerable(
actor, flags, playerUID, gCampaign.Entry.Mode, damage))
actor, d.Flags, playerUID, gCampaign.Entry.Mode, d.Special))
{
return;
}
ActorTakeSpecialDamage(actor, damage, specialTicks);
ActorTakeSpecialDamage(actor, d.Special, d.SpecialTicks);

// Update hits
// TODO: correct accuracy for persistent bullets
if (!gCampaign.IsClient && playerUID >= 0 &&
strlen(d.SourceWeaponClassName) > 0)
{
PlayerData *p = PlayerDataGetByUID(playerUID);
const WeaponClass *wc = StrWeaponClass(d.SourceWeaponClassName);
WeaponUsagesUpdate(p->WeaponUsages, wc, 0, 1);
}
}

bool ActorIsInvulnerable(
Expand Down
18 changes: 16 additions & 2 deletions src/cdogs/bullet_class.c
Original file line number Diff line number Diff line change
Expand Up @@ -644,8 +644,8 @@ static void OnHit(HitItemData *data, Thing *target)
data->HitType = GetHitType(target, data->Obj, &targetUID);
const TActor *source = ActorGetByUID(data->Obj->ActorUID);
Damage(
data->Obj->thing.Vel, data->Obj->bulletClass, data->Obj->flags, source,
target->kind, targetUID);
data->Obj->thing.Vel, data->Obj->bulletClass, data->Obj->weapon,
data->Obj->flags, source, target->kind, targetUID);
if (target->SoundLock <= 0)
{
target->SoundLock += SOUND_LOCK_THING;
Expand Down Expand Up @@ -1084,13 +1084,27 @@ void BulletAdd(const NAddBullet add)
obj->flags |= FLAGS_HURTALWAYS;
}

obj->weapon = StrWeaponClass(add.Gun);

obj->isInUse = true;
obj->thing.drawFunc = NULL;
obj->thing.drawData.MobObjId = i;
obj->thing.CPic = obj->bulletClass->CPic;
obj->thing.CPicFunc = BulletDraw;
obj->thing.ShadowSize = obj->bulletClass->ShadowSize;
MapTryMoveThing(&gMap, &obj->thing, pos);

// Update shots
if (!gCampaign.IsClient)
{
const TActor *source = ActorGetByUID(add.ActorUID);
const int playerUID = source != NULL ? source->PlayerUID : -1;
PlayerData *p = PlayerDataGetByUID(playerUID);
if (p)
{
WeaponUsagesUpdate(p->WeaponUsages, obj->weapon, 1, 0);
}
}
}

void BulletBounce(const NBulletBounce bb)
Expand Down
112 changes: 60 additions & 52 deletions src/cdogs/damage.c
Original file line number Diff line number Diff line change
@@ -1,50 +1,50 @@
/*
C-Dogs SDL
A port of the legendary (and fun) action/arcade cdogs.
Copyright (C) 1995 Ronny Wester
Copyright (C) 2003 Jeremy Chin
Copyright (C) 2003-2007 Lucas Martin-King
C-Dogs SDL
A port of the legendary (and fun) action/arcade cdogs.
Copyright (C) 1995 Ronny Wester
Copyright (C) 2003 Jeremy Chin
Copyright (C) 2003-2007 Lucas Martin-King
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
This file incorporates work covered by the following copyright and
permission notice:
This file incorporates work covered by the following copyright and
permission notice:
Copyright (c) 2013-2015, 2018-2019 Cong Xu
All rights reserved.
Copyright (c) 2013-2015, 2018-2019 Cong Xu
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#include "damage.h"

Expand All @@ -58,7 +58,6 @@
// make blood spurt further
#define MELEE_VEL_SCALE 40.0f


bool CanHitCharacter(const int flags, const int uid, const TActor *actor)
{
// Don't let players hurt themselves
Expand All @@ -70,15 +69,16 @@ bool CanHitCharacter(const int flags, const int uid, const TActor *actor)
}

bool CanDamageCharacter(
const int flags, const TActor *source,
const TActor *target, const special_damage_e special)
const int flags, const TActor *source, const TActor *target,
const special_damage_e special)
{
if (!CanHitCharacter(flags, source ? source->uid : -1, target))
{
return false;
}
return !ActorIsInvulnerable(
target, flags, source ? source->PlayerUID : -1, gCampaign.Entry.Mode, special);
target, flags, source ? source->PlayerUID : -1, gCampaign.Entry.Mode,
special);
}

static void TrackKills(PlayerData *pd, const TActor *victim);
Expand All @@ -87,17 +87,24 @@ void DamageActor(TActor *victim, const int power, const int sourceActorUID)
const int startingHealth = victim->health;
InjureActor(victim, power);
const TActor *source = ActorGetByUID(sourceActorUID);
if (startingHealth > 0 && victim->health <= 0 &&
source != NULL && source->PlayerUID >= 0)
// Track kills and hits
if (source != NULL)
{
TrackKills(PlayerDataGetByUID(source->PlayerUID), victim);
PlayerData *pd = PlayerDataGetByUID(source->PlayerUID);
if (pd != NULL)
{
if (startingHealth > 0 && victim->health <= 0)
{
TrackKills(pd, victim);
}
}
}
}
static void TrackKills(PlayerData *pd, const TActor *victim)
{
if (!IsPVP(gCampaign.Entry.Mode) &&
(victim->PlayerUID >= 0 ||
(victim->flags & (FLAGS_GOOD_GUY | FLAGS_PENALTY))))
(victim->flags & (FLAGS_GOOD_GUY | FLAGS_PENALTY))))
{
pd->Stats.Friendlies++;
pd->Totals.Friendlies++;
Expand All @@ -117,18 +124,18 @@ static void TrackKills(PlayerData *pd, const TActor *victim)
void DamageMelee(const NActorMelee m)
{
const TActor *a = ActorGetByUID(m.UID);
if (!a->isInUse) return;
if (!a->isInUse)
return;
const BulletClass *b = StrBulletClass(m.BulletClass);
if ((HitType)m.HitType != HIT_NONE &&
HasHitSound((ThingKind)m.TargetKind, m.TargetUID,
SPECIAL_NONE, false))
HasHitSound((ThingKind)m.TargetKind, m.TargetUID, SPECIAL_NONE, false))
{
PlayHitSound(b, (HitType)m.HitType, a->Pos);
}
if (!gCampaign.IsClient)
{
const Thing *target = ThingGetByUID(
(ThingKind)m.TargetKind, m.TargetUID);
const Thing *target =
ThingGetByUID((ThingKind)m.TargetKind, m.TargetUID);
const struct vec2 vel = svec2_scale(
svec2_add(
svec2_normalize(svec2_subtract(target->Pos, a->Pos)),
Expand All @@ -137,6 +144,7 @@ void DamageMelee(const NActorMelee m)
RAND_FLOAT(-MELEE_SPREAD_FACTOR, MELEE_SPREAD_FACTOR))),
MELEE_VEL_SCALE);
Damage(
vel, b, a->flags, a, (ThingKind)m.TargetKind, m.TargetUID);
vel, b, NULL, // Don't track hits/accuracy for melee weapons
a->flags, a, (ThingKind)m.TargetKind, m.TargetUID);
}
}
28 changes: 28 additions & 0 deletions src/cdogs/net_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,28 @@ bool NetDecode(ENetPacket *packet, void *dest, const pb_msgdesc_t *fields)
return status;
}

typedef struct
{
map_t src;
NPlayerData *d;
} AddWeaponUsageData;
static int AddWeaponUsage(any_t data, any_t key)
{
AddWeaponUsageData *aData = (AddWeaponUsageData *)data;
// TODO: copy weapon usage
NWeaponUsage *w;
int error = hashmap_get(aData->src, (char *)key, (any_t *)&w);
if (error != MAP_OK)
{
return error;
}
NWeaponUsage *n = &aData->d->WeaponUsages[aData->d->WeaponUsages_count];
strcpy(n->Weapon, (char *)key);
n->Shots = w->Shots;
n->Hits = w->Hits;
aData->d->WeaponUsages_count++;
return MAP_OK;
}
NPlayerData NMakePlayerData(const PlayerData *p)
{
NPlayerData d = NPlayerData_init_default;
Expand Down Expand Up @@ -85,6 +107,12 @@ NPlayerData NMakePlayerData(const PlayerData *p)
{
strcpy(d.Weapons[i], p->guns[i] != NULL ? p->guns[i]->name : "");
}
d.WeaponUsages_count = 0;
AddWeaponUsageData aData;
aData.src = p->WeaponUsages;
aData.d = &d;
hashmap_iterate_keys(p->WeaponUsages, AddWeaponUsage, &aData);

d.Lives = p->Lives;
d.Stats = p->Stats;
d.Totals = p->Totals;
Expand Down
2 changes: 1 addition & 1 deletion src/cdogs/net_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
#include "map.h"
#include "player.h"

#define NET_PROTOCOL_VERSION 15
#define NET_PROTOCOL_VERSION 16

// Messages

Expand Down
Loading

0 comments on commit 3eba2e8

Please sign in to comment.