Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ctf Frogbots #365

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open

Conversation

SpookyScaryDev
Copy link
Contributor

Allowed KTX Frogbots to play CTF matches. There are a lot of changes here so I appreciate it will probably take a long time to get this to the point where it can be merged, but I will try and respond as quickly as possible :)

General Features / Changes

  • Added a new command 'botcmd gomarker' for k_fb_options 3 < 3. Bots will all abandon their current goals and run to the marker the player was looking at when they used this command. Useful for debugging movement on complex maps. This command is admin only.
  • Added functionality for bots to shoot buttons and doors. This has to be added explicitly in the .bot file.
    • Added a new path flag LOOK_BUTTON. This marks a path from a regular marker to a button. Bots won't move along this path, it is used to show them where to look when shooting the button.
  • Increased NUMBER_SUBZONES from 32 to 128, since all the CTF maps have very large rooms. This is not strictly necessary, but it makes adding support to maps much easier.
  • Bots will abandon goals if a teammate is already going for them, except artefacts and flags.

CTF Support

  • Bots now play CTF! They will (attempt to) capture and return the flag and grab runes.
    • Bots prioritise runes in this order, from best to worst: res, str, hst, rgn
  • Bots each have one of 3 roles - attack, defend, midfield
    • Attackers will try and cap the flag
    • Midfielders will prioritise quad
    • Defenders will stay closer to the base and try to defend
    • Defence points are set manually in the .bot file.
    • Bots are added with roles in this order: attacker, midfield, defend, attack, midfield, etc.
    • Depending on the bots role, it will ignore the distance of relevant goals when deciding a goal
  • Bots will prioritise enemies carrying their flag.
  • Bots carrying a flag won't chase enemies.
  • Increased bot lookahead time for CTF.
  • Bots can now use the grappling hook. Hook paths must be added explicitly in the .bot file.
  • Updated bot messages.
    • Going for flag
    • Base safe / not safe
    • All messages include whether the bot has the flag / which rune they have.
  • For CTF, .bot filenames must end in _ctf to distinguish them from other modes, as the item ids are different.
  • On E2M2, bots on the red team will grab lg and discharge when they first spawn.
  • Added CTF names (this is just for fun and I can remove them if you want!)

Known Issues

These are all not too high priority as far as I can tell, and I haven't been able to figure them out so far.

  • team1 and team2 spawns were not automatically turned into markers. Unfortunately, I noticed this relatively late on, so all the .bot files I made have a custom marker right next to all the spawn points instead. It would be easy to fix the spawn points to make them markers automatically, but this would ruin the marker numbering in all the bot files I created and any other bot files created for maps with these spawns.
  • If a player adds some bots, changes teams and adds more bots, some of the bots will be the wrong colour on the scoreboard. Can't work out why this is as it works fine in 4on4.
  • All the movement debug logging doesn't include hook routes yet.
  • I had to add checks for NULL to bot_botenemy.c, line 140 due to crashes. As far as I can tell, this could have caused crashes anyway, I'm not sure if this is linked to the CTF code or not.

There are several other parts where I'm not sure if I've made good decisions or not, these are marked in my code with 'TODO hiipe', I can summarise these here if that would be preferable.

I hope that covers everything, this is my first time trying to contribute to a big project like this, so I would appreciate any feedback.

Thanks,
hiipe

@dsvensson
Copy link
Collaborator

dsvensson commented Sep 5, 2024

Very nice to see it finally proposed! Currently all the CI jobs fail. You can see the output in your own repository:

https://github.com/SpookyScaryDev/ktx/actions/runs/10723857587

It would be nice if you could trim down this massive amount of commits to a bit fewer commits. No need to keep all your back and forth attempts, typos and whatnot, in this fairly isolated (from human gameplay perspective) PR. In your description you mention standalone bugfixes which are typically something nice to have in separate commit(s). Trimming down number of commits would probably also make a rebase less painful instead of the merge-with-master which likely broke the build for you. Prettier to deal with the build-breakage in the commits that introduce them during a rebase. My personal opinion is that each commit should contribute discrete value or lay the foundation for future commits to do so, and the tree should be in a functional state at each point in history. If it feels dumb to write an elaborate commit message for a specific commit, then perhaps that commit should be folded into a related commit. But that's just my own take, not the law of the project.

If going that route, I would propose you reset back to before the merge commit, then git rebase -i 934ea13bee69888940fd08b2ab78d9ff81032b1b (point of diverge) and shuffle around your commits and clean up history, and then rebase on top of upstream master. As you're 18 months behind master, you could rebase in steps to have a breather before rebasing further into the future so you don't have to deal with all the pain at once. At each step you can just push to verify that CI passes on platforms not native to you. If you stumble across some breakage, then commit that and shuffle it into the commit that introduced it with another git rebase -i $ancestor.

The conflicts and build failures ought to be fairly limited to strict-prototypes, that is, no empty () declarations for functions (which allows passing an arbitrary amount of parameters to void functions, cought a number of bugs). The other potential reason might be changes that were made to make QVM target compileable again, mostly c89isch fixes like moving declarations to start of block. Once you've cleaned up your history, it should probably be fairly quick to deal with the conflicts during the rebase.

In the future, keep feature branch duration short, and rebase often to minimize pain.

There are also a number of FIXME's and TODO's in there as you mention that ought to be resolved, or elaborated on, or removed and created issues for on merge. If merged, they will be there 10 years from now.

In addition to the CI errors, there are a number of warnings added that are valid complaints (some of them ought to be errors even, but that's OT here). Browse through them and see what cleanups you might want to do. Can probably skip looking at the macOS build, as it has so many type warnings in upstream atm, have a fix for it but will wait with that until you're done to not cause additional pain.

Will do a deeper read later.

...and for future inspiration https://x.com/GuangyuRobert/status/1831006762184646829 :)

@dsvensson
Copy link
Collaborator

@SpookyScaryDev no need to close, you can just push -f to the same branch.

Copy link
Collaborator

@dsvensson dsvensson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Phew... there was an end after all took the whole train ride to read. Haven't tried running it yet. Would be nice if you could introduce some .bot files in a separate commit in the resources/example-configs/ktx/bots/maps/ dir, or if you go with the review comment, resources/example-configs/ktx/bots/maps/ctf/ dir. Overall it looks pretty good, gj!

Getting rid of accidental unrelated code changes in the last commit is trivial,

# 's' to split a hunk into smaller pieces, y/n to accept, q once you've fixed the last one to avoid hammering 'n'.
git checkout -p HEAD^ -- src/route_calc.c # sample, don't recall which files had some minor issues
git diff --cached # verify that you have staged what you intend to undo
git commit --amend

Always nice to leave blame on someone else :)

if (player->ctf_flag & CTF_RUNE_MASK)
{
int newRune = rune->ctf_flag;
int currentRune = player->ctf_flag & 15;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

15 -> CTF_RUNE_MASK, but could also do something like this which has established use in other parts of the code base:

int currentRune;
if ((currentRune = player->ctf_flag & CTF_RUNE_MASK)) {
    ...
}

@@ -172,6 +167,8 @@ static fb_spawn_t stdSpawnFunctions[] =
{ "door", fb_spawn_door }, // covers func_door and func_door_secret
{ "func_button", fb_spawn_button },
{ "info_player_deathmatch", fb_spawn_spawnpoint },
//{ "info_player_team1", fb_spawn_spawnpoint }, // TODO hiipe - these should be in here, but adding them will mean having to
//{ "info_player_team2", fb_spawn_spawnpoint }, // put all ctf map files through a script to correct the numbering. Later...
Copy link
Collaborator

@dsvensson dsvensson Sep 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's also info_player_team1_deathmatch and info_player_team1_deathmatch available to CTF when using k_ctf_based_spawn. Currently a severe lack of maps using it as it's a bit unknown. When enabled and match has started, players have a 50% chance to pick a info_player_teamX_deathmatch spawn or a info_player_deathmatch spawn. An example usecase would be to have more info_player_teamX_deathmatch near home base, and more info_player_deathmatch near mid, to weight respawns a bit towards home base rather than going all in k_ctf_based_spawn.

As for having to update the current CTF-specific e2m2.bot file etc, do that before the merge to avoid getting into a situation where more files have this problem. It's complete crap that the indices changes based on this list, but is what it is.

#define MARKER_FLAG1_DEFEND 2048 // Point used to defend flag 1 (red)
#define MARKER_FLAG2_DEFEND 4096 // Point used to defend flag 1 (blue)
#define MARKER_LOOK_BUTTON 8192 // A button can be shot from this marker - set automatically
#define MARKER_E2M2_DISCHARGE 16384 // Bots on red team will run here then discharge at the start of the map
Copy link
Collaborator

@dsvensson dsvensson Sep 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should probably gain a better name than MARKER_E2M2_DISCHARGE. Perhaps MARKER_MATCH_START_DISCHARGE or so unless you can think of something shorter. Might be a usecase on future or past maps even if the most common one happens to be on e2m2. Perhaps MARKER_IS_DM6_DOOR tricked you into map-specific naming.

@@ -419,7 +419,7 @@ typedef void (*fb_entity_funcref_t)(struct gedict_s* item);
#define NUMBER_PATHS 8
#endif
#ifndef NUMBER_SUBZONES
#define NUMBER_SUBZONES 32
#define NUMBER_SUBZONES 128 // TODO hiipe - check this, should be ok though?
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All arrays indexed by subzones uses this for size, so I can't find any reason for why this wouldn't be fine. Perhaps read through and verify yourself to remove your uncertainties, and finally the comment. It will only spread uncertainties for the next person reading it.

@@ -9,6 +9,7 @@
#define ATTACK_RESPAWN_TIME 3

qbool DM6FireAtDoor(gedict_t *self, vec3_t rel_pos);
qbool E2M2DischargeLogic(gedict_t* self);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment as the define name, get rid of map specific names in favor of more explanatory names. It's a generic feature that only happens to be commonly associated with e2m2.


// Load bot definition file: frogbots rely on objects spawning
// markers, so be aware of alternative .ent files
char *entityFile = cvar_string("k_entityfile");
if (isCTF()) strlcat(entityFile, "_ctf", sizeof(entityFile));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sv_loadentfiles_dir ctf I wonder if it's too ugly to simply use that cvar for .bot files as well. It would fix the problem, and it's only ever set to something other than "" for CTF in the example configs, which are likely very similar to the nquakesv-configs that everyone uses.

@@ -52,12 +52,41 @@ static void TravelTimeForPath(gedict_t *m, int i)
player_speed = sv_maxspeed * (1 + max(0, DotProduct(distance, hor_distance)));

// FIXME: RJ time is guideline, but we can do better than this?
m->fb.paths[i].time = 100000;
m->fb.paths[i].time = 1000000;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Accidental change? If not it would be great with an explaination.


// TODO hiipe - work out time correctly!
m->fb.paths[i].time = /*1000000*/(total_distance / player_speed);
//m->fb.paths[i].hook_time = (total_distance / player_speed);
Copy link
Collaborator

@dsvensson dsvensson Sep 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it work at all? Needs more work? Otherwise as with other stuff, file a GH issue with context and possibly half baked ideas. Perhaps someone else happens to read it and implement it for you compared to hiding it in the code. Should probably start using labels in GH issues for ctf, bots etc in the issues for discoverability.

zone->next_hook = path->next_marker;

no_change = false;
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

move move down to its if (zone->hook_time ... buddy?

@@ -713,20 +764,38 @@ static void TeamplayReportTaken(gedict_t *client)
}
else if ((NEED(needFlags, it_health) || NEED(needFlags, it_armor) || NEED(needFlags, it_rl)
|| NEED(needFlags, it_lg) || NEED(needFlags, it_rockets)
|| NEED(needFlags, it_cells)) && HAVE_POWERUP(client))
|| NEED(needFlags, it_cells)))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

brainz hurts, getting near bottom, is there any risk of something not HAVE_POWERUP(client) and not isCTF() && (HAVE_FLAG(client) || HAVE_RUNE(client)) slips through here and produces some weird "need " message?

@mushis
Copy link
Contributor

mushis commented Sep 19, 2024

This is almost unrelated to this ticket, and im sorry for that. Yesterday I played 2on2 with bots (deathmatch) and when it comes to Quad (well, powerups I believe), they are very stupid. I mean, they steal the Quad while Im there, they get in the way.
I was happy when I read the above:

Bots will abandon goals if a teammate is already going for them, except artefacts and flags.

And I just wanted to make sure this use case has been fixed - not only for CTF but for other game modes too!
If you prefer, I can open a issue.

@tcsabina
Copy link
Collaborator

@SpookyScaryDev,

How do you see the comments from @dsvensson ?

@SpookyScaryDev
Copy link
Contributor Author

@tcsabina Yes, thanks for the poke. I will try and get this done over the next week! And thanks @dsvensson for all the amazing help and feedback :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants