From 581af99aeca131ebe2bf9fe5b498dc72d7d8e28b Mon Sep 17 00:00:00 2001 From: NeonKnightOA Date: Sun, 9 Feb 2020 14:26:53 -0300 Subject: [PATCH 1/4] Extended DOM support for the AI. This one adds the following features: - Basic (yet open to improvements) AI logic - Team formations - Team orders for classic UI and MP UI --- botfiles/inv.h | 177 ++++++++ botfiles/match.h | 146 +++++++ botfiles/syn.h | 34 ++ botfiles/teamplay.h | 561 ++++++++++++++++++++++++++ code/game/ai_cmd.c | 116 ++++++ code/game/ai_cmd.h | 2 + code/game/ai_dmnet.c | 69 ++-- code/game/ai_dmq3.c | 131 ++++-- code/game/ai_dmq3.h | 2 + code/game/ai_main.c | 10 + code/game/ai_main.h | 8 +- code/game/ai_team.c | 80 ++++ code/game/ai_vcmd.c | 41 ++ code/game/match.h | 1 + code/q3_ui/ui_teamorders.c | 35 ++ ui/menudef.h | 1 + windows_scripts/git-bash-compile.bash | 4 + 17 files changed, 1358 insertions(+), 60 deletions(-) create mode 100644 botfiles/inv.h create mode 100644 botfiles/match.h create mode 100644 botfiles/syn.h create mode 100644 botfiles/teamplay.h diff --git a/botfiles/inv.h b/botfiles/inv.h new file mode 100644 index 00000000..6b5c904f --- /dev/null +++ b/botfiles/inv.h @@ -0,0 +1,177 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code 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. + +Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#define INVENTORY_NONE 0 +//armor +#define INVENTORY_ARMOR 1 +//weapons +#define INVENTORY_GAUNTLET 4 +#define INVENTORY_SHOTGUN 5 +#define INVENTORY_MACHINEGUN 6 +#define INVENTORY_GRENADELAUNCHER 7 +#define INVENTORY_ROCKETLAUNCHER 8 +#define INVENTORY_LIGHTNING 9 +#define INVENTORY_RAILGUN 10 +#define INVENTORY_PLASMAGUN 11 +#define INVENTORY_BFG10K 13 +#define INVENTORY_GRAPPLINGHOOK 14 +#define INVENTORY_NAILGUN 15 +#define INVENTORY_PROXLAUNCHER 16 +#define INVENTORY_CHAINGUN 17 +//ammo +#define INVENTORY_SHELLS 18 +#define INVENTORY_BULLETS 19 +#define INVENTORY_GRENADES 20 +#define INVENTORY_CELLS 21 +#define INVENTORY_LIGHTNINGAMMO 22 +#define INVENTORY_ROCKETS 23 +#define INVENTORY_SLUGS 24 +#define INVENTORY_BFGAMMO 25 +#define INVENTORY_NAILS 26 +#define INVENTORY_MINES 27 +#define INVENTORY_BELT 28 +//powerups +#define INVENTORY_HEALTH 29 +#define INVENTORY_TELEPORTER 30 +#define INVENTORY_MEDKIT 31 +#define INVENTORY_KAMIKAZE 32 +#define INVENTORY_PORTAL 33 +#define INVENTORY_INVULNERABILITY 34 +#define INVENTORY_QUAD 35 +#define INVENTORY_ENVIRONMENTSUIT 36 +#define INVENTORY_HASTE 37 +#define INVENTORY_INVISIBILITY 38 +#define INVENTORY_REGEN 39 +#define INVENTORY_FLIGHT 40 +#define INVENTORY_SCOUT 41 +#define INVENTORY_GUARD 42 +#define INVENTORY_DOUBLER 43 +#define INVENTORY_AMMOREGEN 44 + +#define INVENTORY_REDFLAG 45 +#define INVENTORY_BLUEFLAG 46 +#define INVENTORY_NEUTRALFLAG 47 +#define INVENTORY_REDCUBE 48 +#define INVENTORY_BLUECUBE 49 +//Elimination mod: Domination inventory +#define INVENTORY_POINTWHITE 50 +#define INVENTORY_POINTRED 51 +#define INVENTORY_POINTBLUE 52 + +//enemy stuff +#define ENEMY_HORIZONTAL_DIST 200 +#define ENEMY_HEIGHT 201 +#define NUM_VISIBLE_ENEMIES 202 +#define NUM_VISIBLE_TEAMMATES 203 + +//item numbers (make sure they are in sync with bg_itemlist in bg_misc.c) +#define MODELINDEX_ARMORSHARD 1 +#define MODELINDEX_ARMORCOMBAT 2 +#define MODELINDEX_ARMORBODY 3 +#define MODELINDEX_HEALTHSMALL 4 +#define MODELINDEX_HEALTH 5 +#define MODELINDEX_HEALTHLARGE 6 +#define MODELINDEX_HEALTHMEGA 7 + +#define MODELINDEX_GAUNTLET 8 +#define MODELINDEX_SHOTGUN 9 +#define MODELINDEX_MACHINEGUN 10 +#define MODELINDEX_GRENADELAUNCHER 11 +#define MODELINDEX_ROCKETLAUNCHER 12 +#define MODELINDEX_LIGHTNING 13 +#define MODELINDEX_RAILGUN 14 +#define MODELINDEX_PLASMAGUN 15 +#define MODELINDEX_BFG10K 16 +#define MODELINDEX_GRAPPLINGHOOK 17 + +#define MODELINDEX_SHELLS 18 +#define MODELINDEX_BULLETS 19 +#define MODELINDEX_GRENADES 20 +#define MODELINDEX_CELLS 21 +#define MODELINDEX_LIGHTNINGAMMO 22 +#define MODELINDEX_ROCKETS 23 +#define MODELINDEX_SLUGS 24 +#define MODELINDEX_BFGAMMO 25 + +#define MODELINDEX_TELEPORTER 26 +#define MODELINDEX_MEDKIT 27 +#define MODELINDEX_QUAD 28 +#define MODELINDEX_ENVIRONMENTSUIT 29 +#define MODELINDEX_HASTE 30 +#define MODELINDEX_INVISIBILITY 31 +#define MODELINDEX_REGEN 32 +#define MODELINDEX_FLIGHT 33 + +#define MODELINDEX_REDFLAG 34 +#define MODELINDEX_BLUEFLAG 35 + +// mission pack only defines + +#define MODELINDEX_KAMIKAZE 36 +#define MODELINDEX_PORTAL 37 +#define MODELINDEX_INVULNERABILITY 38 + +#define MODELINDEX_NAILS 39 +#define MODELINDEX_MINES 40 +#define MODELINDEX_BELT 41 + +#define MODELINDEX_SCOUT 42 +#define MODELINDEX_GUARD 43 +#define MODELINDEX_DOUBLER 44 +#define MODELINDEX_AMMOREGEN 45 + +#define MODELINDEX_NEUTRALFLAG 46 +#define MODELINDEX_REDCUBE 47 +#define MODELINDEX_BLUECUBE 48 + +#define MODELINDEX_NAILGUN 49 +#define MODELINDEX_PROXLAUNCHER 50 +#define MODELINDEX_CHAINGUN 51 + +//Elimination mod: Double Domination and Standard Domination + +#define MODELINDEX_POINTABLUE 52 +#define MODELINDEX_POINTBBLUE 53 +#define MODELINDEX_POINTARED 54 +#define MODELINDEX_POINTBRED 55 +#define MODELINDEX_POINTAWHITE 56 +#define MODELINDEX_POINTBWHITE 57 +#define MODELINDEX_POINTWHITE 58 +#define MODELINDEX_POINTRED 59 +#define MODELINDEX_POINTBLUE 60 + + + +// +#define WEAPONINDEX_GAUNTLET 1 +#define WEAPONINDEX_MACHINEGUN 2 +#define WEAPONINDEX_SHOTGUN 3 +#define WEAPONINDEX_GRENADE_LAUNCHER 4 +#define WEAPONINDEX_ROCKET_LAUNCHER 5 +#define WEAPONINDEX_LIGHTNING 6 +#define WEAPONINDEX_RAILGUN 7 +#define WEAPONINDEX_PLASMAGUN 8 +#define WEAPONINDEX_BFG 9 +#define WEAPONINDEX_GRAPPLING_HOOK 10 +#define WEAPONINDEX_NAILGUN 11 +#define WEAPONINDEX_PROXLAUNCHER 12 +#define WEAPONINDEX_CHAINGUN 13 diff --git a/botfiles/match.h b/botfiles/match.h new file mode 100644 index 00000000..45c65f08 --- /dev/null +++ b/botfiles/match.h @@ -0,0 +1,146 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code 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. + +Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +// make sure this is the same character as we use in chats in g_cmd.c +#define EC "\x19" + +//match template contexts +#define MTCONTEXT_MISC 2 +#define MTCONTEXT_INITIALTEAMCHAT 4 +#define MTCONTEXT_TIME 8 +#define MTCONTEXT_TEAMMATE 16 +#define MTCONTEXT_ADDRESSEE 32 +#define MTCONTEXT_PATROLKEYAREA 64 +#define MTCONTEXT_REPLYCHAT 128 +#define MTCONTEXT_CTF 256 +#define MTCONTEXT_DD 512 + +//message types +#define MSG_NEWLEADER 1 //new leader +#define MSG_ENTERGAME 2 //enter game message +#define MSG_HELP 3 //help someone +#define MSG_ACCOMPANY 4 //accompany someone +#define MSG_DEFENDKEYAREA 5 //defend a key area +#define MSG_RUSHBASE 6 //everyone rush to base +#define MSG_GETFLAG 7 //get the enemy flag +#define MSG_STARTTEAMLEADERSHIP 8 //someone wants to become the team leader +#define MSG_STOPTEAMLEADERSHIP 9 //someone wants to stop being the team leader +#define MSG_WHOISTEAMLAEDER 10 //who is the team leader +#define MSG_WAIT 11 //wait for someone +#define MSG_WHATAREYOUDOING 12 //what are you doing? +#define MSG_JOINSUBTEAM 13 //join a sub-team +#define MSG_LEAVESUBTEAM 14 //leave a sub-team +#define MSG_CREATENEWFORMATION 15 //create a new formation +#define MSG_FORMATIONPOSITION 16 //tell someone his/her position in a formation +#define MSG_FORMATIONSPACE 17 //set the formation intervening space +#define MSG_DOFORMATION 18 //form a known formation +#define MSG_DISMISS 19 //dismiss commanded team mates +#define MSG_CAMP 20 //camp somewhere +#define MSG_CHECKPOINT 21 //remember a check point +#define MSG_PATROL 22 //patrol between certain keypoints +#define MSG_LEADTHEWAY 23 //lead the way +#define MSG_GETITEM 24 //get an item +#define MSG_KILL 25 //kill someone +#define MSG_WHEREAREYOU 26 //where is someone +#define MSG_RETURNFLAG 27 //return the flag +#define MSG_WHATISMYCOMMAND 28 //ask the team leader what to do +#define MSG_WHICHTEAM 29 //ask which team a bot is in +#define MSG_TASKPREFERENCE 30 //tell your teamplay task preference +#define MSG_ATTACKENEMYBASE 31 //attack the enemy base +#define MSG_HARVEST 32 //go harvest +#define MSG_SUICIDE 33 //order to suicide +// + +//Double Domination messages +#define MSG_TAKEA 90 +#define MSG_TAKEB 91 +#define MSG_HOLDDOMPOINT 92 //defend a DOM point +// +#define MSG_ME 100 +#define MSG_EVERYONE 101 +#define MSG_MULTIPLENAMES 102 +#define MSG_NAME 103 +#define MSG_PATROLKEYAREA 104 +#define MSG_MINUTES 105 +#define MSG_SECONDS 106 +#define MSG_FOREVER 107 +#define MSG_FORALONGTIME 108 +#define MSG_FORAWHILE 109 +// +#define MSG_CHATALL 200 +#define MSG_CHATTEAM 201 +#define MSG_CHATTELL 202 +// +#define MSG_CTF 300 //ctf message + + + +//command sub types +#define ST_SOMEWHERE 0 +#define ST_NEARITEM 1 +#define ST_ADDRESSED 2 +#define ST_METER 4 +#define ST_FEET 8 +#define ST_TIME 16 +#define ST_HERE 32 +#define ST_THERE 64 +#define ST_I 128 +#define ST_MORE 256 +#define ST_BACK 512 +#define ST_REVERSE 1024 +#define ST_SOMEONE 2048 +#define ST_GOTFLAG 4096 +#define ST_CAPTUREDFLAG 8192 +#define ST_RETURNEDFLAG 16384 +#define ST_TEAM 32768 +#define ST_1FCTFGOTFLAG 65535 + + +//ctf task preferences +#define ST_DEFENDER 1 +#define ST_ATTACKER 2 +#define ST_ROAMER 4 + + +//word replacement variables +#define THE_ENEMY 7 +#define THE_TEAM 7 +//team message variables +#define NETNAME 0 +#define PLACE 1 +#define FLAG 1 +#define MESSAGE 2 +#define ADDRESSEE 2 +#define ITEM 3 +#define TEAMMATE 4 +#define TEAMNAME 4 +#define ENEMY 4 +#define KEYAREA 5 +#define FORMATION 5 +#define POSITION 5 +#define NUMBER 5 +#define TIME 6 +#define NAME 6 +#define MORE 6 + + + diff --git a/botfiles/syn.h b/botfiles/syn.h new file mode 100644 index 00000000..d63c5765 --- /dev/null +++ b/botfiles/syn.h @@ -0,0 +1,34 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code 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. + +Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#define CONTEXT_ALL 0xFFFFFFFF +#define CONTEXT_NORMAL 1 +#define CONTEXT_NEARBYITEM 2 +#define CONTEXT_CTFREDTEAM 4 +#define CONTEXT_CTFBLUETEAM 8 +#define CONTEXT_REPLY 16 +#define CONTEXT_OBELISKREDTEAM 32 +#define CONTEXT_OBELISKBLUETEAM 64 +#define CONTEXT_HARVESTERREDTEAM 128 +#define CONTEXT_HARVESTERBLUETEAM 256 + +#define CONTEXT_NAMES 1024 diff --git a/botfiles/teamplay.h b/botfiles/teamplay.h new file mode 100644 index 00000000..c5151591 --- /dev/null +++ b/botfiles/teamplay.h @@ -0,0 +1,561 @@ +/* +=========================================================================== +Copyright (C) 2006 Dmn_clown (aka: Bob Isaac (rjisaac@gmail.com)) + +This file is part of Open Arena and is based upon Mr. Elusive's fuzzy logic +system found in Quake 3 Arena. + +Open Arena 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. + +Open Arena 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 Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + + //the bot doesn't know who someone is +type "whois" +{ +"Ok, so who is ", 0, "?"; +"Who in their right mind uses the name ", 0, "?"; +"Who in the hell is ", 0, "?"; +"Is ", 0, " a friend of yours?"; +"Who the bloodyhell is ",0," ."; +0, "!?! Who dat?"; +"How can I kill ", 0, " when I haven't the foggiest idea who ", 0, " is?"; + +} + + //the bot doesn't know where someone is hanging out +type "whereis" +{ +"So where is ", 0, "?"; +"Ok, so where is", 0, "."; +"Would someone please tell me where ", 0, " is."; +" ", 0, " hanging out?"; +"Where the hell is ", 0, "?"; +"Since when am I ", 0, "'s keeper?"; +} + + //the bot asks where you are +type "whereareyou" +{ +"Yo, where are you ", 0, "?"; +"Hello!! ", 0, "Where are you hiding?"; +"I can't find you ", 0, ". Where are you?"; +"Where did you scuttle off to ", 0, "?"; +"How am I supposed to find you, ", 0, "?"; +} + +//cannot find something +type "cannotfind" +{ +"Where would that be ", 0, "?"; +"Where the hell is a ", 0, "?"; +"Where is a ", 0, " in this level?"; +"Is there a, ", 0, " in this level? I sure can't find it, I must be blind."; +} + + //bot tells where he/she is +type "location" +{ +"By the ", 0," what are you blind?"; +"I am at the ", 0; +} + +//bot tells where he/she is and near which base +type "teamlocation" +{ +"I'm near the ", 0, " in the ", 1, "base."; +"By the ", 0, " in the ", 1, " base."; +} + + //start helping +type "help_start" +{ +"I'm almost there, ", 0, ", coming to help."; +"Ok, I'm on my way,", 0,"."; +"Keep 'em busy, ", 0," I'm on my way."; +} + + //start accompanying +type "accompany_start" +{ +"Consider me your shadow ", 0 ,"."; +affirmative, "... what else have I got planned?"; + +} + + //stop accompanying +type "accompany_stop" +{ +"It's been real, but I'm off on my own, ", 0,"."; +"I'm on my own now."; +"Good luck, I'm off on my own."; +} + + //cannot find companion +type "accompany_cannotfind" +{ +"Where the hell are you ", 0, "?"; +"Where are you hiding ", 0, "?"; +0, "... come out, come out wherever you are..."; + +} + + //arrived at companion +type "accompany_arrive" +{ +"At your disposal ", 0, "."; +"Finally, I've found ", 0, "."; +"Better late than never, eh?"; + +} + //bot decides to accompany flag or skull carrier +type "accompany_flagcarrier" +{ +"I've got your back ", 0, "."; +"They'll have to get through me to get to you, ", 0, "."; +"Following."; + +} + + //start defending a key area +type "defend_start" +{ +"I'll defend the ", 0, "."; +"I'm defending the ", 0, "."; + +} + + //stop defending a key area +type "defend_stop" +{ +"That's it, I'll stop defending the ", 0, "."; +"I am not defending the ", 0, "."; +"I am not going to defend the ", 0, " anymore."; + +} + + //start getting an item +type "getitem_start" +{ +"I'll get the ", 0, "."; +"I'm off to get the ", 0, "."; + +} + //item is not there +type "getitem_notthere" +{ +"the ", 0, " ain't there"; +"The ", 0, " seems to be missing."; +"Where is the ", 0, "?"; +} + //picked up the item +type "getitem_gotit" +{ +"I got the ", 0, "!"; +"The ", 0, " is mine!"; + +} + + //go kill someone +type "kill_start" +{ +"I'm going to kill ", 0,", wish me luck."; +0, " will be toast."; +0, " is a goner."; +0, " will be given a pair of cement shoes."; +"Ok"; +"What ever you say"; +"Finally some fun!"; +} + //killed the person +type "kill_done" +{ +"Well that was easy. ", 0, " is dead."; +0, " has been wacked."; +0, " was given cement shoes."; +0, " kicked the bucket."; +0, " was taken out."; +0, " just bought the farm."; +0, " is now just dust in the wind."; +} + + //start camping +type "camp_start" +{ +"That is a good sniping position."; +"Off to pitch my tent."; +"Sounds like a plan."; +} + + //stop camping +type "camp_stop" +{ +"Time to move on."; +"Sniping isn't so good here, moving on."; +} + + //in camp position +type "camp_arrive" //0 = one that ordered the bot to camp +{ +"I'm there. ", 0, ", time to snipe."; +"Tent pitched, sniping at will."; + +} + + //start patrolling +type "patrol_start" //0 = locations +{ +"Patrolling ", 0, "."; + +} + + //stop patrolling +type "patrol_stop" +{ +"The patrol is over, nothing to report."; +} + + //start trying to capture the enemy flag +type "captureflag_start" +{ +"Their flag will be ours."; +"Sounds like a plan."; +"I'm off to get the flag."; +"Enemy flag here I come."; + +} + + //return the flag +type "returnflag_start" +{ +"I'll get our flag back."; +"I'll get the flag back."; +"I will return the flag."; + +} + + //attack enemy base +type "attackenemybase_start" +{ +"Got it, their base is toast."; +"I'm off to destroy their base and frag a few fools."; +"Death to the infidels!"; + +} + + //harvest +type "harvest_start" +{ +"Death to the infidels! Their skulls will be mine!"; +"Death to the infidels!"; +"The infidels shall die!"; +} + + //the checkpoint is invalid +type "checkpoint_invalid" +{ +"That checkpoint does not exist."; +"Quit fooling around, that is not a checkpoint."; +} + + //confirm the checkpoint +type "checkpoint_confirm" //0 = name, 1 = gps +{ +affirmative, " Yep ", 0, " at ", 1, " is there."; +"It looks like ", 0, " at ", 1, " is there."; +} + + //follow me +type "followme" +{ +"What the hell are you waiting for ", 0, "? Get over here!"; +"Hey! ", 0, " follow me and be quick about it."; +} + + //stop leading +type "lead_stop" +{ +"That's it find someone else who wants the responsibility."; +"I refuse to lead anymore."; +"I do not want to lead anymore, find someone else."; +} + + //the bot is helping someone +type "helping" +{ +"I'm trying to help, ", 0, "."; +"Helping ", 0, ", care to join me?"; +} + + //the bot is accompanying someone +type "accompanying" +{ +"I'm shadowing ", 0, ". Is that alright?"; +"Following ", 0, ", trying not to get shot."; +} + + //the bot is defending something +type "defending" +{ +"I'm defending ", 0, "."; + +} + + //the bot is going for an item +type "gettingitem" +{ +"I'm off to get the ", 0, "."; +"The ", 0, " is going to be mine."; +"Dibs on the ", 0, "."; +} + + //trying to kill someone +type "killing" +{ +"I've been trying to kill ", 0, "."; +"Trying to wack ", 0, "."; +} + + //the bot is camping +type "camping" +{ +"Toasting marshmallows and sniping scum."; +"Where I am supposed to be, camping."; +"Sniping, just like you told me."; +} + + //the bot is patrolling +type "patrolling" +{ +"On patrol, can't talk now."; +} + + //the bot is capturing the flag +type "capturingflag" +{ +"Gots to get the flag."; +} + + //the bot is rushing to the base +type "rushingbase" +{ +"Rushing to the base."; +} + + //trying to return the flag +type "returningflag" +{ +"Getting the flag back."; +} + +type "attackingenemybase" +{ +"I'm destroying their base! Care to help?"; +"Wreaking havok in their base."; +} + +type "harvesting" +{ +"Collecting skulls, what are you doing?"; +} + + //the bot is just roaming a bit +type "roaming" +{ +"Rambling around, fragging at whim."; +"Mindlessly roaming around, like I was told."; +"~Wacking fools piece-meal."; +} + +type "wantoffence" +{ +"Let me go on offense."; +"Can I be on offense?"; + +} + +type "wantdefence" +{ +"I think I can handle the big D."; +"Can I be on defense?"; +} + + //the bot will keep the team preference in mind +type "keepinmind" +{ +"A'ight, ", 0," I'll keep it in mind."; + +} + + //========================== + // teamplay chats + //========================== + //team mate killed the bot +type "death_teammate" +{ +"Same team, dumbass!"; +"Hey ", 0," I'm on your team... idiot!"; +"Why did you kill me?"; +} + //killed by a team mate +type "kill_teammate" +{ +"hehe... oops."; +"Sorry!"; +"Oops, won't happen again."; +} + + //========================== + // CTF useless chats + //========================== + + //team mate got the enemy flag +type "ctf_gotflag" +{ +"It's about time, ", 0, " now get that flag home!"; +} + //team mate gets the enemy flag to the base +type "ctf_captureflag" +{ +"Sweet, gj, ", 0, "."; +} + //team mate returns the base flag +type "ctf_returnflag" +{ +"Nice assist, ", 0, "."; +} //end type + //team mate defends the base +type "ctf_defendbase" +{ +"Nice D work there, ", 0, "."; +} + //team mate carrying the enemy flag dies +type "ctf_flagcarrierdeath" +{ +"Go get our flag!"; +} + //team mate kills enemy with base flag +type "ctf_flagcarrierkill" +{ +"Yo, ", 0," get our flag now!"; +} + + //========================== + // NOTE: make sure these work with match.c + //========================== + //ask who the team leader is +type "whoisteamleader" +{ +"Who's the leader of this rag-tag bunch?"; +} + + //I am the team leader +type "iamteamleader" +{ +"I am the leader."; +"I shall lead."; +"I lead."; +} + //defend the base command +type "cmd_defendbase" +{ +0, " defend our base."; +0, " set up some D."; +0, " you should defend our base."; +} + //get the enemy flag command +type "cmd_getflag" +{ +"Yo, ", 0, " get the flag!"; +0, " get their flag."; +0, " capture the other team's flag."; +} + //accompany someone command +type "cmd_accompany" +{ +"Hey, ", 0, " shadow ", 1; +0, " follow ", 1, ", ", 1, " needs the help."; + +} + //accompany me command +type "cmd_accompanyme" +{ +0, " you should follow me."; +"Follow me please, ", 0, "."; +} + //attack enemy base command +type "cmd_attackenemybase" +{ +0, " go after their base"; +} + //return the flag command +type "cmd_returnflag" +{ +0, " please return our flag!"; +0, " get our flag back, ASAP!"; +} + //go harvesting +type "cmd_harvest" +{ +0, ", you should collect some skulls."; +} + + //Double Domination stuff: +type "dd_start_pointa" +{ +"I'll dominate point A"; +} + +type "dd_start_pointb" +{ +"I'll dominate point B"; +} + +type "dd_pointa" +{ +"Dominating point A"; +} + +type "dd_pointb" +{ +"Dominating point B"; +} + +//DD orders: +type "cmd_takea" +{ +0, " dominate point A"; +} + +type "cmd_takeb" +{ +0, " dominate point B"; +} + +//Domination stuff: +type "dom_point_hold_start" +{ + "I'll pick a control point and hold it!"; +} + +type "dom_point_holding" +{ + "Holding control of ", 1; +} + +//Domination orders: +type "cmd_holddompoint" +{ + 0, " pick a control point and defend it!"; +} diff --git a/code/game/ai_cmd.c b/code/game/ai_cmd.c index e8516dd7..6c54962e 100644 --- a/code/game/ai_cmd.c +++ b/code/game/ai_cmd.c @@ -142,6 +142,11 @@ void BotPrintTeamGoal(bot_state_t *bs) { BotAI_Print(PRT_MESSAGE, "%s: I'm gonna take care of point B for %1.0f secs\n", netname, t); break; } + case LTG_HOLDDOMPOINT: + { + BotAI_Print(PRT_MESSAGE, "%s: I'm gonna defend a DOM point for %1.0f secs\n", netname, t); + break; + } default: { if (bs->ctfroam_time > FloatTime()) { @@ -474,6 +479,48 @@ int BotGPSToPosition(char *buf, vec3_t position) { return qtrue; } +void BotMatch_HoldDOMPoint(bot_state_t *bs, bot_match_t *match); + +/* +================== +BotSetDominationPoint +Selects a point for Domination. It's saved in the field currentPoint. +================== +*/ +void BotSetDominationPoint(bot_state_t *bs, int controlPoint) { + int i; + qboolean allTaken = qtrue; + + // Domination only + if (gametype != GT_DOMINATION) return; + // If there are no points, just assign the neutral one. + if (level.domination_points_count > 1) { + bs->currentPoint = 0; + return; + } + // If a control point point has been passed, + // and falls inside of both gametype AND map limits, assign it. + if (controlPoint >= 0 && + controlPoint < level.domination_points_count && + controlPoint < MAX_DOMINATION_POINTS) { + bs->currentPoint = controlPoint; + return; + } + // Search for points our team don't own. + for (i=1;icurrentPoint = i; + break; + } + } + // If we own all of the points, operate in a random one. + if (allTaken == qfalse) { + bs->currentPoint = rand() % level.domination_points_count; + } +} + /* ================== BotMatch_HelpAccompany @@ -611,6 +658,13 @@ void BotMatch_DefendKeyArea(bot_state_t *bs, bot_match_t *match) { int client; if (!G_IsATeamGametype(gametype)) return; + // Domination has clear rules + if (gametype == GT_DOMINATION) { + // Reroll to get a different DOM point. + BotSetDominationPoint(bs,-1); + BotMatch_HoldDOMPoint(bs,match); + return; + } //if not addressed to this bot if (!BotAddressedToBot(bs, match)) return; //get the match variable @@ -746,6 +800,48 @@ void BotMatch_TakeB(bot_state_t *bs, bot_match_t *match) { #endif //DEBUG } +/* +================== +BotMatch_HoldDOMPoint +For Domination +================== +*/ +void BotMatch_HoldDOMPoint(bot_state_t *bs, bot_match_t *match) { + char netname[MAX_MESSAGE_SIZE]; + int client; + + if (gametype != GT_DOMINATION) return; + if (level.domination_points_count < 1) return; + //if not addressed to this bot + if (!BotAddressedToBot(bs, match)) return; + //get the match variable + // + trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname)); + // + client = ClientFromName(netname); + //the team mate who ordered + bs->decisionmaker = client; + bs->ordered = qtrue; + bs->order_time = FloatTime(); + //set the time to send a message to the team mates + bs->teammessage_time = FloatTime() + 2 * random(); + //set the ltg type + bs->ltgtype = LTG_HOLDDOMPOINT; + //get the team goal time + bs->teamgoal_time = BotGetTime(match); + //set the team goal time + if (!bs->teamgoal_time) bs->teamgoal_time = FloatTime() + TEAM_HOLDDOMPOINT_TIME; + //away from defending + bs->defendaway_time = 0; + // + BotSetTeamStatus(bs); + // remember last ordered task + BotRememberLastOrderedTask(bs); +#ifdef DEBUG + BotPrintTeamGoal(bs); +#endif //DEBUG +} + /* ================== BotMatch_GetItem @@ -988,6 +1084,12 @@ void BotMatch_AttackEnemyBase(bot_state_t *bs, bot_match_t *match) { if (!redobelisk.areanum || !blueobelisk.areanum) return; } + else if (gametype == GT_DOMINATION) { + // Reroll to get a different DOM point. + BotSetDominationPoint(bs,-1); + BotMatch_HoldDOMPoint(bs,match); + return; + } else { return; } @@ -1546,6 +1648,11 @@ void BotMatch_WhatAreYouDoing(bot_state_t *bs, bot_match_t *match) { BotAI_BotInitialChat(bs, "dd_pointb", NULL); break; } + case LTG_HOLDDOMPOINT: + { + BotAI_BotInitialChat(bs, "dom_holdpoint", NULL); + break; + } default: { BotAI_BotInitialChat(bs, "roaming", NULL); @@ -1867,6 +1974,10 @@ void BotMatch_EnterGame(bot_state_t *bs, bot_match_t *match) { if (client >= 0) { notleader[client] = qfalse; } + if (gametype == GT_DOMINATION) { + // Assign a control point at start. + BotSetDominationPoint(bs,-1); + } //NOTE: eliza chats will catch this //Com_sprintf(buf, sizeof(buf), "heya %s", netname); //EA_Say(bs->client, buf); @@ -2083,6 +2194,11 @@ int BotMatchMessage(bot_state_t *bs, char *message) { BotMatch_TakeB(bs, &match); break; } + case MSG_HOLDDOMPOINT: + { + BotMatch_HoldDOMPoint(bs, &match); + break; + } default: { BotAI_Print(PRT_MESSAGE, "unknown match type\n"); diff --git a/code/game/ai_cmd.h b/code/game/ai_cmd.h index dd10bc19..314427c3 100644 --- a/code/game/ai_cmd.h +++ b/code/game/ai_cmd.h @@ -35,3 +35,5 @@ extern int notleader[MAX_CLIENTS]; int BotMatchMessage(bot_state_t *bs, char *message); void BotPrintTeamGoal(bot_state_t *bs); +// Neon_Knight: Used for DOM point assignment +void BotSetDominationPoint(bot_state_t *bs, int controlPoint); diff --git a/code/game/ai_dmnet.c b/code/game/ai_dmnet.c index b47f6968..2df7b284 100644 --- a/code/game/ai_dmnet.c +++ b/code/game/ai_dmnet.c @@ -580,37 +580,6 @@ int BotGetLongTermGoal(bot_state_t *bs, int tfl, int retreat, bot_goal_t *goal) } return qtrue; } - //if (bs->ltgtype == LTG_DOMHOLD && - // bs->defendaway_time < FloatTime()) { - //check for bot typing status message - /*if (bs->teammessage_time && bs->teammessage_time < FloatTime()) { - trap_BotGoalName(bs->teamgoal.number, buf, sizeof(buf)); - BotAI_BotInitialChat(bs, "dd_start_pointb", buf, NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_TEAM); - //BotVoiceChatOnly(bs, -1, VOICECHAT_ONDEFENSE); - bs->teammessage_time = 0; - }*/ - //set the bot goal - // memcpy(goal, &bs->teamgoal, sizeof(bot_goal_t)); - //if very close... go away for some time - // VectorSubtract(goal->origin, bs->origin, dir); - // if (VectorLengthSquared(dir) < Square(30)) { - /*trap_BotResetAvoidReach(bs->ms); - bs->defendaway_time = FloatTime() + 3 + 3 * random(); - if (BotHasPersistantPowerupAndWeapon(bs)) { - bs->defendaway_range = 100; - } - else { - bs->defendaway_range = 350; - }*/ - // memcpy(&bs->teamgoal, &dom_points_bot[((rand()) % (level.domination_points_count))], sizeof(bot_goal_t)); - // BotAlternateRoute(bs, &bs->teamgoal); - // BotSetTeamStatus(bs); - - //} - //return qtrue; - - // } //if defending a key area if (bs->ltgtype == LTG_DEFENDKEYAREA && !retreat && bs->defendaway_time < FloatTime()) { @@ -1111,7 +1080,43 @@ int BotGetLongTermGoal(bot_state_t *bs, int tfl, int retreat, bot_goal_t *goal) return qtrue; } } -//#endif + else if (gametype == GT_DOMINATION) { + // If the bot has an assigned control point that falls outside of the limits, + // assign a new one before proceeding. + if (!(bs->currentPoint >= 0 && + bs->currentPoint < MAX_DOMINATION_POINTS && + bs->currentPoint < level.domination_points_count)) { + BotSetDominationPoint(bs,-1); + } + if ((bs->ltgtype == LTG_DEFENDKEYAREA) || + (bs->ltgtype == LTG_ATTACKENEMYBASE) || + (bs->ltgtype == LTG_HOLDDOMPOINT)) { + //check for bot typing status message + if (bs->teammessage_time && bs->teammessage_time < FloatTime()) { + trap_BotGoalName(bs->teamgoal.number, buf, sizeof(buf)); + BotAI_BotInitialChat(bs, "dom_point_hold_start", buf, level.domination_points_names[bs->currentPoint]); + trap_BotEnterChat(bs->cs, 0, CHAT_TEAM); + //BotVoiceChatOnly(bs, -1, VOICECHAT_ONDEFENSE); + bs->teammessage_time = 0; + } + //set the bot goal + memcpy(goal, &dom_points_bot[bs->currentPoint], sizeof(bot_goal_t)); + //if very close... go away for some time + VectorSubtract(goal->origin, bs->origin, dir); + if (VectorLengthSquared(dir) < Square(70)) { + trap_BotResetAvoidReach(bs->ms); + bs->defendaway_time = FloatTime() + 3 + 3 * random(); + if (BotHasPersistantPowerupAndWeapon(bs)) { + bs->defendaway_range = 100; + } + else { + bs->defendaway_range = 350; + } + } + return qtrue; + } + } + //normal goal stuff return BotGetItemLongTermGoal(bs, tfl, goal); } diff --git a/code/game/ai_dmq3.c b/code/game/ai_dmq3.c index 7c7d0ece..a01b5256 100644 --- a/code/game/ai_dmq3.c +++ b/code/game/ai_dmq3.c @@ -444,6 +444,23 @@ void BotSetTeamStatus(bot_state_t *bs) { else teamtask = TEAMTASK_DEFENSE; break; + case LTG_HOLDDOMPOINT: + // If the bot has an invalid CP, reroll. + if (!(bs->currentPoint >= 0 && + bs->currentPoint < MAX_DOMINATION_POINTS && + bs->currentPoint < level.domination_points_count)) { + BotSetDominationPoint(bs,-1); + } + if ((BotTeam(bs) == TEAM_BLUE && level.pointStatusDom[bs->currentPoint] == TEAM_BLUE) || + (BotTeam(bs) == TEAM_RED && level.pointStatusDom[bs->currentPoint] == TEAM_RED)) + teamtask = TEAMTASK_DEFENSE; + else if ((BotTeam(bs) == TEAM_BLUE && level.pointStatusDom[bs->currentPoint] != TEAM_BLUE) || + (BotTeam(bs) == TEAM_RED && level.pointStatusDom[bs->currentPoint] != TEAM_RED)) + teamtask = TEAMTASK_OFFENSE; + else { + teamtask = TEAMTASK_PATROL; + } + break; default: teamtask = TEAMTASK_PATROL; break; @@ -823,29 +840,92 @@ void BotCTFRetreatGoals(bot_state_t *bs) { BotDomSeekGoals ================== */ - -/*void BotDomSeekGoals(bot_state_t *bs) { - int index; - bs->ltgtype = LTG_DOMHOLD; //For debugging we are forcing roam - - index=0; - //dom_points_bot[i] - - if(bs->ltgtype == LTG_DOMHOLD) { - //index = 0; - index = ((rand()) % (level.domination_points_count)); - } - - //if(bs->ltgtype == LTG_DOMROAM) { - - //} - - memcpy(&bs->teamgoal, &dom_points_bot[index], sizeof(bot_goal_t)); - - BotAlternateRoute(bs, &bs->teamgoal); - - BotSetTeamStatus(bs); -}*/ +void BotDomSeekGoals(bot_state_t *bs) { + float rnd, l1; + + // DD only + if (gametype != GT_DOMINATION) return; + // if the map has no points, just roam + if (level.domination_points_count < 1) { + bs->ltgtype = LTG_PATROL; + BotSetUserInfo(bs, "teamtask", va("%d", TEAMTASK_PATROL)); + BotSetTeamStatus(bs); + return; + } + // don't just do something wait for the bot team leader to give orders + if (BotTeamLeader(bs)) { + return; + } + // if the bot is ordered to do something + if (bs->lastgoal_ltgtype) { + bs->teamgoal_time += 60; + } + // if the bot decided to do something on it's own and has a last ordered goal + if (!bs->ordered && bs->lastgoal_ltgtype) { + bs->ltgtype = 0; + } + //if already a CTF or team goal + if (bs->ltgtype == LTG_TEAMHELP || + bs->ltgtype == LTG_TEAMACCOMPANY || + bs->ltgtype == LTG_CAMPORDER || + bs->ltgtype == LTG_PATROL || + bs->ltgtype == LTG_GETITEM || + bs->ltgtype == LTG_MAKELOVE_UNDER || + bs->ltgtype == LTG_MAKELOVE_ONTOP || + bs->ltgtype == LTG_HOLDDOMPOINT) { + return; + } + // + if (BotSetLastOrderedTask(bs)) + return; + // + if (bs->owndecision_time > FloatTime()) + return; + ; + //if the bot is roaming + if (bs->ctfroam_time > FloatTime()) + return; + //if the bot has enough aggression to decide what to do + if (BotAggression(bs) < 50) + return; + // If the bot has no set control point, reroll + if (!(bs->currentPoint >= 0 && + bs->currentPoint < MAX_DOMINATION_POINTS && + bs->currentPoint < level.domination_points_count)) { + BotSetDominationPoint(bs,-1); + } + //set the time to send a message to the team mates + bs->teammessage_time = FloatTime() + 2 * random(); + // + if (bs->teamtaskpreference & TEAMTP_ATTACKER) { + l1 = 0.7f; + } else { + l1 = 0.2f; + } + //pick a point + rnd = random(); + if (rnd < l1) { + bs->decisionmaker = bs->client; + bs->ordered = qfalse; + // + memcpy(&bs->teamgoal, &dom_points_bot[bs->currentPoint], sizeof (bot_goal_t)); + //set the ltg type + bs->ltgtype = LTG_HOLDDOMPOINT; + //set the time the bot stops defending the base + bs->teamgoal_time = FloatTime() + TEAM_HOLDDOMPOINT_TIME; + bs->defendaway_time = 0; + BotSetTeamStatus(bs); + } else { + bs->ltgtype = LTG_PATROL; + //set the time the bot will stop roaming + bs->ctfroam_time = FloatTime() + CTF_ROAM_TIME; + BotSetTeamStatus(bs); + } + bs->owndecision_time = FloatTime() + 5; +#ifdef DEBUG + BotPrintTeamGoal(bs); +#endif //DEBUG +} /* ================== @@ -1443,8 +1523,8 @@ void BotTeamGoals(bot_state_t *bs, int retreat) { if (gametype == GT_DOUBLE_D) //Don't care about retreat BotDDSeekGoals(bs); - //if(gametype == GT_DOMINATION) //Don't care about retreat - // BotDomSeekGoals(bs); + if(gametype == GT_DOMINATION) //Don't care about retreat + BotDomSeekGoals(bs); // reset the order time which is used to see if // we decided to refuse an order @@ -1767,6 +1847,7 @@ void BotCheckItemPickup(bot_state_t *bs, int *oldinventory) { //trap_BotEnterChat(bs->cs, leader, CHAT_TELL); } else if ((bot_spSkill.integer <= 3) && (bs->ltgtype != LTG_DEFENDKEYAREA) && + (bs->ltgtype != LTG_HOLDDOMPOINT) && ((!(G_UsesTeamFlags(gametype) && !G_UsesTheWhiteFlag(gametype))) || ((bs->redflagstatus == 0) && (bs->blueflagstatus == 0))) && diff --git a/code/game/ai_dmq3.h b/code/game/ai_dmq3.h index ca7ecc56..02b19a24 100644 --- a/code/game/ai_dmq3.h +++ b/code/game/ai_dmq3.h @@ -142,6 +142,8 @@ void BotRememberLastOrderedTask(bot_state_t *bs); void BotCTFSeekGoals(bot_state_t *bs); //set ctf goals (defend base, get enemy flag) during retreat void BotCTFRetreatGoals(bot_state_t *bs); +//set dom goals (take/defend point) during seek +void BotDomSeekGoals(bot_state_t *bs); // int Bot1FCTFCarryingFlag(bot_state_t *bs); int BotHarvesterCarryingCubes(bot_state_t *bs); diff --git a/code/game/ai_main.c b/code/game/ai_main.c index 85742aff..aadf3744 100644 --- a/code/game/ai_main.c +++ b/code/game/ai_main.c @@ -388,6 +388,11 @@ void BotReportStatus(bot_state_t *bs) { BotAI_Print(PRT_MESSAGE, "%-20s%s%s: going for point B\n", netname, leader, flagstatus); break; } + case LTG_HOLDDOMPOINT: + { + BotAI_Print(PRT_MESSAGE, "%-20s%s%s: defending a DOM control point\n", netname, leader, flagstatus); + break; + } default: { BotAI_Print(PRT_MESSAGE, "%-20s%s%s: roaming\n", netname, leader, flagstatus); @@ -548,6 +553,11 @@ void BotSetInfoConfigString(bot_state_t *bs) { Com_sprintf(action, sizeof(action), "going for point B"); break; } + case LTG_HOLDDOMPOINT: + { + Com_sprintf(action, sizeof(action), "defending a DOM point"); + break; + } default: { trap_BotGetTopGoal(bs->gs, &goal); diff --git a/code/game/ai_main.h b/code/game/ai_main.h index 0e2d3158..97700a77 100644 --- a/code/game/ai_main.h +++ b/code/game/ai_main.h @@ -61,9 +61,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA //Long term DD goals #define LTG_POINTA 16 //Take/Defend point A #define LTG_POINTB 17 //Take/Defend point B -//Long term DD goals -#define LTG_DOMROAM 18 //Go for a non taken point. -#define LTG_DOMHOLD 19 //Pick a point and hold it. +//Long term DOM goals +#define LTG_HOLDDOMPOINT 19 //Defend a DOM point //some goal dedication times #define TEAM_HELP_TIME 60 //1 minute teamplay help time #define TEAM_ACCOMPANY_TIME 600 //10 minutes teamplay accompany time @@ -82,6 +81,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA //Time for Double Domination tasks #define DD_POINTA 600 #define DD_POINTB 600 +//Time for Domination tasks +#define TEAM_HOLDDOMPOINT_TIME 600 //patrol flags #define PATROL_LOOP 1 #define PATROL_REVERSE 2 @@ -245,6 +246,7 @@ typedef struct bot_state_s float teamgoal_time; //time to stop helping team mate float teammatevisible_time; //last time the team mate was NOT visible int teamtaskpreference; //team task preference + int currentPoint; //current DD/DOM point the bot cares about // last ordered team goal int lastgoal_decisionmaker; int lastgoal_ltgtype; diff --git a/code/game/ai_team.c b/code/game/ai_team.c index 4b20b75e..7537d739 100644 --- a/code/game/ai_team.c +++ b/code/game/ai_team.c @@ -2104,6 +2104,68 @@ void BotHarvesterOrders(bot_state_t *bs) { } } +/* +================== +BotDomOrders + +All will roam. +================== +*/ +/*void BotDomOrders_AllPointsTaken(bot_state_t *bs) { +} + +void BotDomOrders_NoPointsTaken(bot_state_t *bs) { +} + +void BotDomOrders_SomePointsTaken(bot_state_t *bs) { +}*/ +void BotDomOrders_Standard(bot_state_t *bs) { + int numteammates, i; + int teammates[MAX_CLIENTS]; + char name[MAX_NETNAME]; + + if (bot_nochat.integer>2) return; + + //sort team mates by travel time to base + numteammates = BotSortTeamMatesByBaseTravelTime(bs, teammates, sizeof(teammates)); + //sort team mates by CTF preference + BotSortTeamMatesByTaskPreference(bs, teammates, numteammates); + + for (i = 0; i < numteammates; i++) { + // + ClientName(teammates[i], name, sizeof(name)); + BotAI_BotInitialChat(bs, "cmd_holddompoint", name, NULL); + BotSayTeamOrder(bs, teammates[i]); + BotSayVoiceTeamOrder(bs, teammates[i], VOICECHAT_DEFEND); + } +} + +/* +================== +BotDomOrders +================== +*/ +void BotDomOrders(bot_state_t *bs) { + /*int i,pointsTaken=0;*/ + + /*for(i=0;i<=level.domination_points_count;i++) { + if(level.pointStatusDom[i] == BotTeam(bs)) { + pointsTaken++; + } + } + + if (pointsTaken == level.domination_points_count) { + BotDomOrders_AllPointsTaken(bs); + } + else if (pointsTaken == 0) { + BotDomOrders_NoPointsTaken(bs); + } + else if (pointsTaken > (level.domination_points_count/2)) { + BotDomOrders_SomePointsTaken(bs); + }*/ + BotDomOrders_Standard(bs); +} + /* ================== FindHumanTeamLeader @@ -2315,6 +2377,24 @@ void BotTeamAI(bot_state_t *bs) { } break; } + case GT_DOMINATION: + { + //if the number of team mates changed or the domination point status changed + //or someone wants to know what to do + if (bs->numteammates != numteammates || bs->flagstatuschanged || bs->forceorders) { + bs->teamgiveorders_time = FloatTime(); + bs->numteammates = numteammates; + bs->flagstatuschanged = qfalse; + bs->forceorders = qfalse; + } + //if it's time to give orders + if (bs->teamgiveorders_time && bs->teamgiveorders_time < FloatTime() - 3) { + BotDomOrders(bs); + // + bs->teamgiveorders_time = 0; + } + break; + } } } diff --git a/code/game/ai_vcmd.c b/code/game/ai_vcmd.c index 77aa74a8..db3f0876 100644 --- a/code/game/ai_vcmd.c +++ b/code/game/ai_vcmd.c @@ -64,6 +64,36 @@ typedef struct voiceCommand_s void (*func)(bot_state_t *bs, int client, int mode); } voiceCommand_t; +/* +================== +BotVoiceChat_HoldDOMPoint +================== +*/ +void BotVoiceChat_HoldDOMPoint(bot_state_t *bs, int client, int mode) { + //Only valid for Double Domination + if (gametype != GT_DOMINATION) return; + if (level.domination_points_count < 1) return; + + bs->decisionmaker = client; + bs->ordered = qtrue; + bs->order_time = FloatTime(); + //set the time to send a message to the team mates + bs->teammessage_time = FloatTime() + 2 * random(); + //set the ltg type + bs->ltgtype = LTG_HOLDDOMPOINT; + //get the team goal time + bs->teamgoal_time = FloatTime() + TEAM_HOLDDOMPOINT_TIME; + //away from defending + bs->defendaway_time = 0; + // + BotSetTeamStatus(bs); + // remember last ordered task + BotRememberLastOrderedTask(bs); +#ifdef DEBUG + BotPrintTeamGoal(bs); +#endif //DEBUG +} + /* ================== BotVoiceChat_GetFlag @@ -133,6 +163,11 @@ void BotVoiceChat_Offense(bot_state_t *bs, int client, int mode) { // remember last ordered task BotRememberLastOrderedTask(bs); } + else if (gametype == GT_DOMINATION) { + BotSetDominationPoint(bs,-1); + BotVoiceChat_HoldDOMPoint(bs,client,mode); + return; + } else { // @@ -179,6 +214,11 @@ void BotVoiceChat_Defend(bot_state_t *bs, int client, int mode) { default: return; } } + else if (gametype == GT_DOMINATION) { + BotSetDominationPoint(bs,-1); + BotVoiceChat_HoldDOMPoint(bs,client,mode); + return; + } else { return; } @@ -490,6 +530,7 @@ voiceCommand_t voiceCommands[] = { {VOICECHAT_WHOISLEADER, BotVoiceChat_WhoIsLeader }, {VOICECHAT_WANTONDEFENSE, BotVoiceChat_WantOnDefense }, {VOICECHAT_WANTONOFFENSE, BotVoiceChat_WantOnOffense }, + {VOICECHAT_HOLDDOMPOINT, BotVoiceChat_HoldDOMPoint }, {NULL, BotVoiceChat_Dummy} }; diff --git a/code/game/match.h b/code/game/match.h index 57e4c00d..45c65f08 100644 --- a/code/game/match.h +++ b/code/game/match.h @@ -73,6 +73,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA //Double Domination messages #define MSG_TAKEA 90 #define MSG_TAKEB 91 +#define MSG_HOLDDOMPOINT 92 //defend a DOM point // #define MSG_ME 100 #define MSG_EVERYONE 101 diff --git a/code/q3_ui/ui_teamorders.c b/code/q3_ui/ui_teamorders.c index fe0427d5..067a3a93 100644 --- a/code/q3_ui/ui_teamorders.c +++ b/code/q3_ui/ui_teamorders.c @@ -42,6 +42,7 @@ TEAM ORDERS MENU #define ID_LIST_BASE_ORDERS 13 #define ID_LIST_TEAM_ORDERS 14 #define ID_LIST_DD_ORDERS 15 +#define ID_LIST_DOM_ORDERS 16 typedef struct { @@ -173,6 +174,28 @@ static const char *ddMessages[] = { NULL }; +#define NUM_DOM_ORDERS 7 +static const char *domOrders[] = { + "I Am the Leader", + "Follow Me", + "Roam", + "Control a point", + "Camp Here", + "Report", + "I Relinquish Command", + NULL +}; +static const char *domMessages[] = { + "i am the leader", + "%s follow me", + "%s roam", + "%s take control of a point", + "%s camp here", + "%s report", + "i stop being the leader", + NULL +}; + /* =============== UI_TeamOrdersMenu_BackEvent @@ -231,6 +254,12 @@ static void UI_TeamOrdersMenu_SetList( int id ) teamOrdersMenuInfo.list.numitems = NUM_DD_ORDERS; teamOrdersMenuInfo.list.itemnames = ddOrders; break; + + case ID_LIST_DOM_ORDERS: + teamOrdersMenuInfo.list.generic.id = id; + teamOrdersMenuInfo.list.numitems = NUM_DOM_ORDERS; + teamOrdersMenuInfo.list.itemnames = domOrders; + break; } teamOrdersMenuInfo.list.generic.bottom = teamOrdersMenuInfo.list.generic.top + teamOrdersMenuInfo.list.numitems * PROP_HEIGHT; @@ -369,6 +398,9 @@ static void UI_TeamOrdersMenu_ListEvent( void *ptr, int event ) if( teamOrdersMenuInfo.gametype == GT_DOUBLE_D ) { UI_TeamOrdersMenu_SetList( ID_LIST_DD_ORDERS ); } + if( teamOrdersMenuInfo.gametype == GT_DOMINATION ) { + UI_TeamOrdersMenu_SetList( ID_LIST_DOM_ORDERS ); + } else { UI_TeamOrdersMenu_SetList( ID_LIST_TEAM_ORDERS ); } @@ -391,6 +423,9 @@ static void UI_TeamOrdersMenu_ListEvent( void *ptr, int event ) if( id == ID_LIST_DD_ORDERS ) { Com_sprintf( message, sizeof(message), ddMessages[selection], teamOrdersMenuInfo.botNames[teamOrdersMenuInfo.selectedBot] ); } + if( id == ID_LIST_DOM_ORDERS ) { + Com_sprintf( message, sizeof(message), domMessages[selection], teamOrdersMenuInfo.botNames[teamOrdersMenuInfo.selectedBot] ); + } trap_Cmd_ExecuteText( EXEC_APPEND, va( "say_team \"%s\"\n", message ) ); UI_PopMenu(); diff --git a/ui/menudef.h b/ui/menudef.h index b1a53710..d062e8cd 100644 --- a/ui/menudef.h +++ b/ui/menudef.h @@ -379,3 +379,4 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define VOICECHAT_DEATHINSULT "death_insult" // you just killed me #define VOICECHAT_KILLGAUNTLET "kill_gauntlet" // I just killed you with the gauntlet #define VOICECHAT_PRAISE "praise" // you did something good +#define VOICECHAT_HOLDDOMPOINT "holddompoint" // hold a DOM point diff --git a/windows_scripts/git-bash-compile.bash b/windows_scripts/git-bash-compile.bash index d598da38..360fe193 100755 --- a/windows_scripts/git-bash-compile.bash +++ b/windows_scripts/git-bash-compile.bash @@ -5,8 +5,12 @@ cmd.exe "/c windows_compile_game_missionpack.bat" cmd.exe "/c windows_compile_q3_ui.bat" cmd.exe "/c windows_compile_ui_missionpack.bat" pushd ../windows/baseoa +cp -r ../../botfiles botfiles ../../windows_scripts/zip oax.pk3 vm/*.qvm +../../windows_scripts/zip oax.pk3 botfiles/*.* popd pushd ../windows/missionpack +cp -r ../../botfiles botfiles ../../windows_scripts/zip oax-mp.pk3 vm/*.qvm +../../windows_scripts/zip oax-mp.pk3 botfiles/*.* popd From 1d9e9f2a93768087b17ed00fbcb2306605c3f4dd Mon Sep 17 00:00:00 2001 From: NeonKnightOA Date: Sat, 2 Apr 2022 18:48:26 -0300 Subject: [PATCH 2/4] Implemented BotGetDominationPoint(bs). Prevents the direct usage of bs->currentPoint as well as using any variables involving it. Silly you NK! --- code/game/ai_cmd.c | 10 ++++++++++ code/game/ai_cmd.h | 1 + code/game/ai_dmnet.c | 10 +++++----- code/game/ai_dmq3.c | 14 +++++++------- 4 files changed, 23 insertions(+), 12 deletions(-) diff --git a/code/game/ai_cmd.c b/code/game/ai_cmd.c index 6c54962e..5d16eded 100644 --- a/code/game/ai_cmd.c +++ b/code/game/ai_cmd.c @@ -481,6 +481,16 @@ int BotGPSToPosition(char *buf, vec3_t position) { void BotMatch_HoldDOMPoint(bot_state_t *bs, bot_match_t *match); +/* +================== +BotGetDominationPoint +Returns the actual Domination point the bot is acting on. Prevents currentPoint from being accessed directly. +================== +*/ +int BotGetDominationPoint(bot_state_t *bs) { + return bs->currentPoint; +} + /* ================== BotSetDominationPoint diff --git a/code/game/ai_cmd.h b/code/game/ai_cmd.h index 314427c3..3e6c0069 100644 --- a/code/game/ai_cmd.h +++ b/code/game/ai_cmd.h @@ -36,4 +36,5 @@ int BotMatchMessage(bot_state_t *bs, char *message); void BotPrintTeamGoal(bot_state_t *bs); // Neon_Knight: Used for DOM point assignment +int BotGetDominationPoint(bot_state_t *bs); void BotSetDominationPoint(bot_state_t *bs, int controlPoint); diff --git a/code/game/ai_dmnet.c b/code/game/ai_dmnet.c index 2df7b284..ddee6afd 100644 --- a/code/game/ai_dmnet.c +++ b/code/game/ai_dmnet.c @@ -1083,9 +1083,9 @@ int BotGetLongTermGoal(bot_state_t *bs, int tfl, int retreat, bot_goal_t *goal) else if (gametype == GT_DOMINATION) { // If the bot has an assigned control point that falls outside of the limits, // assign a new one before proceeding. - if (!(bs->currentPoint >= 0 && - bs->currentPoint < MAX_DOMINATION_POINTS && - bs->currentPoint < level.domination_points_count)) { + if (!(BotGetDominationPoint(bs) >= 0 && + BotGetDominationPoint(bs) < MAX_DOMINATION_POINTS && + BotGetDominationPoint(bs) < level.domination_points_count)) { BotSetDominationPoint(bs,-1); } if ((bs->ltgtype == LTG_DEFENDKEYAREA) || @@ -1094,13 +1094,13 @@ int BotGetLongTermGoal(bot_state_t *bs, int tfl, int retreat, bot_goal_t *goal) //check for bot typing status message if (bs->teammessage_time && bs->teammessage_time < FloatTime()) { trap_BotGoalName(bs->teamgoal.number, buf, sizeof(buf)); - BotAI_BotInitialChat(bs, "dom_point_hold_start", buf, level.domination_points_names[bs->currentPoint]); + BotAI_BotInitialChat(bs, "dom_point_hold_start", buf, level.domination_points_names[BotGetDominationPoint(bs)]); trap_BotEnterChat(bs->cs, 0, CHAT_TEAM); //BotVoiceChatOnly(bs, -1, VOICECHAT_ONDEFENSE); bs->teammessage_time = 0; } //set the bot goal - memcpy(goal, &dom_points_bot[bs->currentPoint], sizeof(bot_goal_t)); + memcpy(goal, &dom_points_bot[BotGetDominationPoint(bs)], sizeof(bot_goal_t)); //if very close... go away for some time VectorSubtract(goal->origin, bs->origin, dir); if (VectorLengthSquared(dir) < Square(70)) { diff --git a/code/game/ai_dmq3.c b/code/game/ai_dmq3.c index a01b5256..4ff63722 100644 --- a/code/game/ai_dmq3.c +++ b/code/game/ai_dmq3.c @@ -446,16 +446,16 @@ void BotSetTeamStatus(bot_state_t *bs) { break; case LTG_HOLDDOMPOINT: // If the bot has an invalid CP, reroll. - if (!(bs->currentPoint >= 0 && - bs->currentPoint < MAX_DOMINATION_POINTS && - bs->currentPoint < level.domination_points_count)) { + if (!(BotGetDominationPoint(bs) >= 0 && + BotGetDominationPoint(bs) < MAX_DOMINATION_POINTS && + BotGetDominationPoint(bs) < level.domination_points_count)) { BotSetDominationPoint(bs,-1); } - if ((BotTeam(bs) == TEAM_BLUE && level.pointStatusDom[bs->currentPoint] == TEAM_BLUE) || - (BotTeam(bs) == TEAM_RED && level.pointStatusDom[bs->currentPoint] == TEAM_RED)) + if ((BotTeam(bs) == TEAM_BLUE && level.pointStatusDom[BotGetDominationPoint(bs)] == TEAM_BLUE) || + (BotTeam(bs) == TEAM_RED && level.pointStatusDom[BotGetDominationPoint(bs)] == TEAM_RED)) teamtask = TEAMTASK_DEFENSE; - else if ((BotTeam(bs) == TEAM_BLUE && level.pointStatusDom[bs->currentPoint] != TEAM_BLUE) || - (BotTeam(bs) == TEAM_RED && level.pointStatusDom[bs->currentPoint] != TEAM_RED)) + else if ((BotTeam(bs) == TEAM_BLUE && level.pointStatusDom[BotGetDominationPoint(bs)] != TEAM_BLUE) || + (BotTeam(bs) == TEAM_RED && level.pointStatusDom[BotGetDominationPoint(bs)] != TEAM_RED)) teamtask = TEAMTASK_OFFENSE; else { teamtask = TEAMTASK_PATROL; From 79945aae3d4c4014bf59f6a531fd8cb8675e8e77 Mon Sep 17 00:00:00 2001 From: NeonKnightOA Date: Wed, 12 Apr 2023 17:21:25 -0300 Subject: [PATCH 3/4] In Developer mode the bot now reports the targeted DOM point. --- code/game/ai_cmd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/game/ai_cmd.c b/code/game/ai_cmd.c index 5d16eded..057f0ba8 100644 --- a/code/game/ai_cmd.c +++ b/code/game/ai_cmd.c @@ -144,7 +144,7 @@ void BotPrintTeamGoal(bot_state_t *bs) { } case LTG_HOLDDOMPOINT: { - BotAI_Print(PRT_MESSAGE, "%s: I'm gonna defend a DOM point for %1.0f secs\n", netname, t); + BotAI_Print(PRT_MESSAGE, "%s: I'm gonna defend DOM point %i for %1.0f secs\n", netname, BotGetDominationPoint(bs), t); break; } default: From 077f85df3cfd1cf016061bdeef1640771fb82610 Mon Sep 17 00:00:00 2001 From: NeonKnightOA Date: Tue, 12 Mar 2024 20:19:32 +0000 Subject: [PATCH 4/4] Update ai_dmnet.c --- code/game/ai_dmnet.c | 53 -------------------------------------------- 1 file changed, 53 deletions(-) diff --git a/code/game/ai_dmnet.c b/code/game/ai_dmnet.c index 37d094e5..155f8cd0 100644 --- a/code/game/ai_dmnet.c +++ b/code/game/ai_dmnet.c @@ -527,59 +527,6 @@ int BotGetLongTermGoal(bot_state_t *bs, int tfl, int retreat, bot_goal_t *goal) bs->defendaway_time = 0; } } - //For double domination - if (bs->ltgtype == LTG_POINTA && - bs->defendaway_time < FloatTime()) { - //check for bot typing status message - if (bs->teammessage_time && bs->teammessage_time < FloatTime()) { - trap_BotGoalName(bs->teamgoal.number, buf, sizeof(buf)); - BotAI_BotInitialChat(bs, "dd_start_pointa", buf, NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_TEAM); - //BotVoiceChatOnly(bs, -1, VOICECHAT_ONDEFENSE); - bs->teammessage_time = 0; - } - //set the bot goal - memcpy(goal, &ctf_redflag, sizeof(bot_goal_t)); - //if very close... go away for some time - VectorSubtract(goal->origin, bs->origin, dir); - if (VectorLengthSquared(dir) < Square(70)) { - trap_BotResetAvoidReach(bs->ms); - bs->defendaway_time = FloatTime() + 3 + 3 * random(); - if (BotHasPersistantPowerupAndWeapon(bs)) { - bs->defendaway_range = 100; - } - else { - bs->defendaway_range = 350; - } - } - return qtrue; - } - if (bs->ltgtype == LTG_POINTB && - bs->defendaway_time < FloatTime()) { - //check for bot typing status message - if (bs->teammessage_time && bs->teammessage_time < FloatTime()) { - trap_BotGoalName(bs->teamgoal.number, buf, sizeof(buf)); - BotAI_BotInitialChat(bs, "dd_start_pointb", buf, NULL); - trap_BotEnterChat(bs->cs, 0, CHAT_TEAM); - //BotVoiceChatOnly(bs, -1, VOICECHAT_ONDEFENSE); - bs->teammessage_time = 0; - } - //set the bot goal - memcpy(goal, &ctf_blueflag, sizeof(bot_goal_t)); - //if very close... go away for some time - VectorSubtract(goal->origin, bs->origin, dir); - if (VectorLengthSquared(dir) < Square(70)) { - trap_BotResetAvoidReach(bs->ms); - bs->defendaway_time = FloatTime() + 3 + 3 * random(); - if (BotHasPersistantPowerupAndWeapon(bs)) { - bs->defendaway_range = 100; - } - else { - bs->defendaway_range = 350; - } - } - return qtrue; - } //if defending a key area if (bs->ltgtype == LTG_DEFENDKEYAREA && !retreat && bs->defendaway_time < FloatTime()) {