Skip to content

Commit b7bc564

Browse files
committed
created upgrade path to level 50 for mage, knight, and necromancer
1 parent 183f36e commit b7bc564

4 files changed

Lines changed: 144 additions & 33 deletions

File tree

src/ai/ai_class_dmbot.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2081,6 +2081,7 @@ void BOT_DMclass_RunFrame( edict_t *self )
20812081
else
20822082
{
20832083
BOT_DMclass_UseSkeleton(self); // try to spawn skeletons if upgraded and we have less than max
2084+
BOT_DMclass_UseGolem(self); // try to spawn golems if upgraded and we have less than max
20842085
}
20852086

20862087
// Execute the move, or wander

src/ai/ai_local.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,7 @@ void AI_InitAIAbilities(void);
204204
void BOT_DMclass_UseBoost(edict_t* self);
205205
void BOT_DMclass_UseBlinkStrike(edict_t* self);
206206
void BOT_DMclass_UseSkeleton(edict_t* self);
207+
void BOT_DMclass_UseGolem(edict_t* self);
207208
qboolean BOT_DMclass_UseTball(edict_t* self, qboolean forget_enemy);
208209

209210
//ai_util.c

src/ai/bot_abilities.c

Lines changed: 72 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,30 @@ void AI_InitAIAbilities(void)
7777
AIAbilities[NOVA].idealRange = AI_RANGE_SHORT;
7878
AIAbilities[NOVA].RangeWeight[AIWEAP_SNIPER_RANGE] = 0;
7979
AIAbilities[NOVA].RangeWeight[AIWEAP_LONG_RANGE] = 0;
80-
AIAbilities[NOVA].RangeWeight[AIWEAP_MEDIUM_RANGE] = 0; // nova can't hit anything beyond short range
80+
AIAbilities[NOVA].RangeWeight[AIWEAP_MEDIUM_RANGE] = 0; // nova can't hit anything much beyond short range
8181
AIAbilities[NOVA].RangeWeight[AIWEAP_SHORT_RANGE] = 0.5;
8282
AIAbilities[NOVA].RangeWeight[AIWEAP_MELEE_RANGE] = 0.5;
8383

84+
//GLACIAL_SPIKE
85+
AIAbilities[GLACIAL_SPIKE].is_weapon = true;
86+
AIAbilities[GLACIAL_SPIKE].aimType = AI_AIMSTYLE_PREDICTION;
87+
AIAbilities[GLACIAL_SPIKE].idealRange = AI_RANGE_MEDIUM;
88+
AIAbilities[GLACIAL_SPIKE].RangeWeight[AIWEAP_SNIPER_RANGE] = 0.1; // doubleful we'll hit anything
89+
AIAbilities[GLACIAL_SPIKE].RangeWeight[AIWEAP_LONG_RANGE] = 0.2; // likely to miss--fireball is better
90+
AIAbilities[GLACIAL_SPIKE].RangeWeight[AIWEAP_MEDIUM_RANGE] = 0.5; // ideal range for GS
91+
AIAbilities[GLACIAL_SPIKE].RangeWeight[AIWEAP_SHORT_RANGE] = 0.2; // highly likely we'll take some damage
92+
AIAbilities[GLACIAL_SPIKE].RangeWeight[AIWEAP_MELEE_RANGE] = 0;
93+
94+
//FROZEN_ORB
95+
AIAbilities[FROZEN_ORB].is_weapon = true;
96+
AIAbilities[FROZEN_ORB].aimType = AI_AIMSTYLE_PREDICTION_EXPLOSIVE;
97+
AIAbilities[FROZEN_ORB].idealRange = AI_RANGE_MEDIUM;
98+
AIAbilities[FROZEN_ORB].RangeWeight[AIWEAP_SNIPER_RANGE] = 0; // FO will never get this far--don't bother
99+
AIAbilities[FROZEN_ORB].RangeWeight[AIWEAP_LONG_RANGE] = 0.4; // FO explodes due to timeout slightly beyond this range
100+
AIAbilities[FROZEN_ORB].RangeWeight[AIWEAP_MEDIUM_RANGE] = 0.5; // ideal range to actually hit our target
101+
AIAbilities[FROZEN_ORB].RangeWeight[AIWEAP_SHORT_RANGE] = 0.4;
102+
AIAbilities[FROZEN_ORB].RangeWeight[AIWEAP_MELEE_RANGE] = 0.4; // nova is better
103+
84104
//STATIC_FIELD
85105
AIAbilities[STATIC_FIELD].is_weapon = true;
86106
AIAbilities[STATIC_FIELD].aimType = AI_AIMSTYLE_NONE; // radius attack, no aiming needed
@@ -96,7 +116,7 @@ void AI_InitAIAbilities(void)
96116
AIAbilities[LIGHTNING].aimType = AI_AIMSTYLE_INSTANTHIT;
97117
AIAbilities[LIGHTNING].idealRange = AI_RANGE_MEDIUM;
98118
AIAbilities[LIGHTNING].RangeWeight[AIWEAP_SNIPER_RANGE] = 0;
99-
AIAbilities[LIGHTNING].RangeWeight[AIWEAP_LONG_RANGE] = 0.4; // meteor/lightning storm is better
119+
AIAbilities[LIGHTNING].RangeWeight[AIWEAP_LONG_RANGE] = 0.5;
100120
AIAbilities[LIGHTNING].RangeWeight[AIWEAP_MEDIUM_RANGE] = 0.5;
101121
AIAbilities[LIGHTNING].RangeWeight[AIWEAP_SHORT_RANGE] = 0.4; // nova is better
102122
AIAbilities[LIGHTNING].RangeWeight[AIWEAP_MELEE_RANGE] = 0.4;
@@ -116,8 +136,8 @@ void AI_InitAIAbilities(void)
116136
AIAbilities[LIGHTNING_STORM].aimType = AI_AIMSTYLE_INSTANTHIT;
117137
AIAbilities[LIGHTNING_STORM].idealRange = AI_RANGE_SNIPER;
118138
AIAbilities[LIGHTNING_STORM].RangeWeight[AIWEAP_SNIPER_RANGE] = 0.5;
119-
AIAbilities[LIGHTNING_STORM].RangeWeight[AIWEAP_LONG_RANGE] = 0.5;
120-
AIAbilities[LIGHTNING_STORM].RangeWeight[AIWEAP_MEDIUM_RANGE] = 0.4; // fireball/lightning/magicbolt is better
139+
AIAbilities[LIGHTNING_STORM].RangeWeight[AIWEAP_LONG_RANGE] = 0.4; // CL is slightly better (lower risk)
140+
AIAbilities[LIGHTNING_STORM].RangeWeight[AIWEAP_MEDIUM_RANGE] = 0.2; // LS is very risky at this range
121141
AIAbilities[LIGHTNING_STORM].RangeWeight[AIWEAP_SHORT_RANGE] = 0;
122142
AIAbilities[LIGHTNING_STORM].RangeWeight[AIWEAP_MELEE_RANGE] = 0;
123143

@@ -191,6 +211,8 @@ float AI_GetAbilityProjectileVelocity(edict_t* ent, int ability_index)
191211
case MAGICBOLT: return BOLT_SPEED;
192212
case FIREBALL: return (FIREBALL_INITIAL_SPEED + FIREBALL_ADDON_SPEED * slvl);
193213
case PLASMA_BOLT: return (PLASMABOLT_INITIAL_SPEED + PLASMABOLT_ADDON_SPEED * slvl);
214+
case GLACIAL_SPIKE: return (GLACIAL_SPIKE_INITIAL_SPEED + GLACIAL_SPIKE_ADDON_SPEED * slvl);
215+
case FROZEN_ORB: return FROZEN_ORB_SPEED;
194216
}
195217
return 0;
196218
}
@@ -212,10 +234,25 @@ float AI_GetAbilityCost(edict_t* ent, int ability_index)
212234
case PLASMA_BOLT: return PLASMABOLT_COST;
213235
case STATIC_FIELD: return STATICFIELD_COST;
214236
case AMP_DAMAGE: return AMP_DAMAGE_COST;
237+
case GLACIAL_SPIKE: return GLACIAL_SPIKE_COST;
238+
case FROZEN_ORB: return FROZEN_ORB_COST;
215239
}
216240
return 0;
217241
}
218242

243+
// return true if the bot isn't done summoning any minions
244+
qboolean AI_NotDoneSummoning(edict_t* ent)
245+
{
246+
if (ent->myskills.abilities[SKELETON].current_level > 0 && ent->num_skeletons < SKELETON_MAX)
247+
return true;
248+
if (ent->myskills.abilities[GOLEM].current_level > 0 && ent->num_golems < GOLEM_MAX)
249+
return true;
250+
if (ent->myskills.abilities[HELLSPAWN].current_level > 0 && !ent->skull)
251+
return true;
252+
return false;
253+
254+
}
255+
219256
qboolean CanCurseTarget(edict_t* caster, edict_t* target, int type, qboolean isCurse, qboolean vis);
220257

221258
//==========================================
@@ -262,9 +299,9 @@ int BOT_DMclass_ChooseAbility(edict_t* self)
262299
// not enough power cubes to use this ability
263300
if (self->client->pers.inventory[power_cube_index] < AI_GetAbilityCost(self, i))
264301
continue;
265-
// don't try to curse uncurseable targets or use the same curse
302+
// don't try to curse uncurseable targets or use the same curse; also don't curse if we're not done summoning!
266303
if ((i == AMP_DAMAGE || i == WEAKEN || i == LIFE_TAP || i == CURSE)
267-
&& (!CanCurseTarget(self, self->enemy, i, true, false) || que_typeexists(self->enemy->curses, i)))
304+
&& (!CanCurseTarget(self, self->enemy, i, true, false) || que_typeexists(self->enemy->curses, i) || AI_NotDoneSummoning(self)))
268305
continue;
269306

270307
//compare range weights
@@ -296,6 +333,8 @@ void Cmd_LightningStorm_f(edict_t* ent, float skill_mult, float cost_mult);
296333
void Cmd_Plasmabolt_f(edict_t* ent);
297334
void Cmd_StaticField_f(edict_t* ent);
298335
void Cmd_AmpDamage(edict_t* ent);
336+
void Cmd_GlacialSpike_f(edict_t* ent, float skill_mult, float cost_mult);
337+
void Cmd_FrozenOrb_f(edict_t* ent, float skill_mult, float cost_mult);
299338

300339
// aims and fires at enemy using the specified ability
301340
void BOT_DMclass_FireAbility(edict_t* self, int ability_index)
@@ -367,6 +406,8 @@ void BOT_DMclass_FireAbility(edict_t* self, int ability_index)
367406
case PLASMA_BOLT: Cmd_Plasmabolt_f(self); break;
368407
case STATIC_FIELD: Cmd_StaticField_f(self); break;
369408
case AMP_DAMAGE: Cmd_AmpDamage(self); break;
409+
case GLACIAL_SPIKE: Cmd_GlacialSpike_f(self, 1.0, 1.0); break;
410+
case FROZEN_ORB: Cmd_FrozenOrb_f(self, 1.0, 1.0); break;
370411
}
371412
}
372413

@@ -435,11 +476,13 @@ void BOT_DMclass_UseBoost(edict_t* self)
435476

436477
void Cmd_Raise_Skeleton_f(edict_t* ent);
437478
void skeleton_set_bbox(vec3_t mins, vec3_t maxs);
479+
void Cmd_Golem_f(edict_t* ent);
480+
void golem_set_bbox(vec3_t mins, vec3_t maxs);
438481

439482
void BOT_DMclass_UseSkeleton(edict_t* self)
440483
{
441484
// can't use skeleton
442-
if (!V_CanUseAbilities(self, SKELETON, SKELETON_COST+10, false))
485+
if (!V_CanUseAbilities(self, SKELETON, SKELETON_COST, false))
443486
return;
444487
// can't spawn any more
445488
if (self->num_skeletons >= SKELETON_MAX)
@@ -456,4 +499,26 @@ void BOT_DMclass_UseSkeleton(edict_t* self)
456499
return;
457500

458501
Cmd_Raise_Skeleton_f(self);
502+
}
503+
504+
void BOT_DMclass_UseGolem(edict_t* self)
505+
{
506+
// can't use golem
507+
if (!V_CanUseAbilities(self, GOLEM, GOLEM_COST, false))
508+
return;
509+
// can't spawn any more
510+
if (self->num_golems >= GOLEM_MAX)
511+
return;
512+
// get view origin
513+
vec3_t forward, right, start, offset, mins, maxs;
514+
AngleVectors(self->client->v_angle, forward, right, NULL);
515+
VectorSet(offset, 0, 8, self->viewheight - 8);
516+
P_ProjectSource(self->client, self->s.origin, offset, forward, right, start);
517+
// get skeleton bounding box mins and maxs
518+
golem_set_bbox(mins, maxs);
519+
// abort if the skeleton can't fit at start
520+
if (!G_GetSpawnLocation(self, 64, mins, maxs, start, NULL, PROJECT_HITBOX_FAR, false))
521+
return;
522+
523+
Cmd_Golem_f(self);
459524
}

src/ai/bot_spawn.c

Lines changed: 70 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -313,35 +313,73 @@ void BOT_SoldierAssignSkills(edict_t *ent)
313313

314314
void BOT_MageAssignSkills(edict_t* ent)
315315
{
316-
BOT_UpgradeSkill(ent, FIREBALL, 1);
317-
BOT_UpgradeSkill(ent, POWER_REGEN, 3); // clvl 2
318-
BOT_UpgradeSkill(ent, FIREBALL, 9);
319-
BOT_UpgradeSkill(ent, POWER_REGEN, 2); // clvl 8
320-
BOT_UpgradeSkill(ent, METEOR, 10); // clvl 13
321-
//BOT_UpgradeSkill(ent, NOVA, 10);
322-
BOT_UpgradeSkill(ent, FIREBALL, 5);
323-
BOT_UpgradeSkill(ent, METEOR, 5);
324-
//BOT_UpgradeSkill(ent, NOVA, 5);
325-
BOT_UpgradeSkill(ent, LIGHTNING, 10);
326-
BOT_UpgradeSkill(ent, FIREBALL, 10);
327-
BOT_UpgradeSkill(ent, LIGHTNING_STORM, 10);
316+
if (random() > 0.5)
317+
{
318+
// ice/cold-lightning build
319+
BOT_UpgradeSkill(ent, GLACIAL_SPIKE, 1);
320+
BOT_UpgradeSkill(ent, POWER_REGEN, 3); // clvl 2
321+
BOT_UpgradeSkill(ent, GLACIAL_SPIKE, 9);
322+
BOT_UpgradeSkill(ent, POWER_REGEN, 2); // clvl 8
323+
BOT_UpgradeSkill(ent, FROZEN_ORB, 10); // clvl 13
324+
BOT_UpgradeSkill(ent, POWER_REGEN, 5); // clvl 15: PCR is maxed
325+
BOT_UpgradeSkill(ent, NOVA, 10); // clvl 20: all ice skills are level 10
326+
BOT_UpgradeSkill(ent, FROZEN_ORB, 5);
327+
BOT_UpgradeSkill(ent, GLACIAL_SPIKE, 5); // clvl 25
328+
BOT_UpgradeSkill(ent, NOVA, 5); // clvl 28: all ice skills are level 15
329+
BOT_UpgradeSkill(ent, STATIC_FIELD, 10); // clvl 33: lightning build begins with SF, which benefits all skills
330+
BOT_UpgradeSkill(ent, LIGHTNING_STORM, 10);
331+
BOT_UpgradeSkill(ent, LIGHTNING, 10); // clvl 43: all lightning skills are level 10
332+
BOT_UpgradeSkill(ent, STATIC_FIELD, 5);
333+
BOT_UpgradeSkill(ent, LIGHTNING_STORM, 5);
334+
BOT_UpgradeSkill(ent, LIGHTNING, 5); // clvl 50: all lightning skills are level 15
335+
}
336+
else
337+
{
338+
// lightning-ice/cold build
339+
BOT_UpgradeSkill(ent, LIGHTNING, 1);
340+
BOT_UpgradeSkill(ent, POWER_REGEN, 3); // clvl 2
341+
BOT_UpgradeSkill(ent, LIGHTNING, 9);
342+
BOT_UpgradeSkill(ent, POWER_REGEN, 2); // clvl 8
343+
BOT_UpgradeSkill(ent, LIGHTNING_STORM, 10); // clvl 13
344+
BOT_UpgradeSkill(ent, POWER_REGEN, 5); // clvl 15: PCR is maxed
345+
BOT_UpgradeSkill(ent, STATIC_FIELD, 10); // clvl 20: all lightning skills are level 10
346+
BOT_UpgradeSkill(ent, LIGHTNING_STORM, 5);
347+
BOT_UpgradeSkill(ent, LIGHTNING, 5); // clvl 25
348+
BOT_UpgradeSkill(ent, STATIC_FIELD, 5); // clvl 28: all lightning skills are level 15
349+
BOT_UpgradeSkill(ent, GLACIAL_SPIKE, 10); // clvl 33: ice/cold build begins with GS to freeze enemies in-place
350+
BOT_UpgradeSkill(ent, FROZEN_ORB, 10);
351+
BOT_UpgradeSkill(ent, NOVA, 10); // clvl 43: all ice/cold skills are level 10
352+
BOT_UpgradeSkill(ent, GLACIAL_SPIKE, 5);
353+
BOT_UpgradeSkill(ent, FROZEN_ORB, 5);
354+
BOT_UpgradeSkill(ent, NOVA, 5); // clvl 50: all ice/cold skills are level 15
355+
}
328356
}
329357

330358
void BOT_KnightAssignSkills(edict_t* ent)
331359
{
332360
BOT_UpgradeSkill(ent, PLASMA_BOLT, 1);
333361
BOT_UpgradeSkill(ent, ARMOR_REGEN, 1);
334362
BOT_UpgradeSkill(ent, REGENERATION, 1);
335-
BOT_UpgradeSkill(ent, ARMOR_UPGRADE, 10); // clvl 2-7
336-
BOT_UpgradeSkill(ent, REGENERATION, 4);
337-
BOT_UpgradeSkill(ent, VITALITY, 3); // clvl 10
338-
BOT_UpgradeSkill(ent, ARMOR_REGEN, 4); // clvl 11-12
339-
BOT_UpgradeSkill(ent, PLASMA_BOLT, 4); // clvl 13-14
363+
BOT_UpgradeSkill(ent, ARMOR_UPGRADE, 10); // clvl 7
364+
BOT_UpgradeSkill(ent, REGENERATION, 3); // clvl 8
365+
BOT_UpgradeSkill(ent, VITALITY, 4); // clvl 10
366+
BOT_UpgradeSkill(ent, ARMOR_REGEN, 4); // clvl 12
367+
BOT_UpgradeSkill(ent, PLASMA_BOLT, 4); // clvl 14
340368
BOT_UpgradeSkill(ent, POWER_REGEN, 2); // clvl 15
341369
BOT_UpgradeSkill(ent, ARMOR_REGEN, 5);
342-
BOT_UpgradeSkill(ent, REGENERATION, 5); // clvl 20
370+
BOT_UpgradeSkill(ent, REGENERATION, 6); // clvl 21
371+
BOT_UpgradeSkill(ent, PLASMA_BOLT, 5); // clvl 23: all primary skills are level 10
372+
BOT_UpgradeSkill(ent, POWER_REGEN, 4);
373+
BOT_UpgradeSkill(ent, VITALITY, 6); // clvl 28
374+
BOT_UpgradeSkill(ent, ARMOR_UPGRADE, 5);
375+
BOT_UpgradeSkill(ent, ARMOR_REGEN, 5);
376+
BOT_UpgradeSkill(ent, REGENERATION, 5);
377+
BOT_UpgradeSkill(ent, PLASMA_BOLT, 5); // clvl 38: all primary skills are level 15
378+
BOT_UpgradeSkill(ent, RESISTANCE, 5);
379+
BOT_UpgradeSkill(ent, GHOST, 5); // clvl 43
380+
BOT_UpgradeSkill(ent, ARMOR_UPGRADE, 5);
343381
BOT_UpgradeSkill(ent, PLASMA_BOLT, 5);
344-
BOT_UpgradeSkill(ent, POWER_SHIELD, 10);
382+
BOT_UpgradeSkill(ent, POWER_REGEN, 4); // clvl 50
345383
}
346384

347385
void BOT_VampireAssignSkills(edict_t* ent)
@@ -360,13 +398,19 @@ void BOT_VampireAssignSkills(edict_t* ent)
360398

361399
void BOT_NecroAssignSkills(edict_t* ent)
362400
{
401+
BOT_UpgradeSkill(ent, SKELETON, 1);
363402
BOT_UpgradeSkill(ent, POWER_REGEN, 4); // clvl 2
364-
BOT_UpgradeSkill(ent, SKELETON, 10); // clvl 7
365-
BOT_UpgradeSkill(ent, POWER_REGEN, 2); // clvl 8
366-
BOT_UpgradeSkill(ent, AMP_DAMAGE, 10); // clvl 13
367-
BOT_UpgradeSkill(ent, SKELETON, 5); // clvl 16
368-
BOT_UpgradeSkill(ent, STATIC_FIELD, 10); // clvl 21
369-
BOT_UpgradeSkill(ent, AMP_DAMAGE, 5); // clvl 23
403+
BOT_UpgradeSkill(ent, SKELETON, 9); // clvl 7
404+
BOT_UpgradeSkill(ent, GOLEM, 10); // clvl 12: skeleton/golem is level 10
405+
BOT_UpgradeSkill(ent, AMP_DAMAGE, 10); // clvl 17
406+
BOT_UpgradeSkill(ent, LIFE_TAP, 10); // clvl 22: curses are level 10
407+
BOT_UpgradeSkill(ent, POWER_REGEN, 2); // clvl 23
408+
BOT_UpgradeSkill(ent, GOLEM, 10);
409+
BOT_UpgradeSkill(ent, SKELETON, 10); // clvl 33: skeleton/golem is level 20
410+
BOT_UpgradeSkill(ent, AMP_DAMAGE, 10);
411+
BOT_UpgradeSkill(ent, LIFE_TAP, 10); // clvl 43: curses are level 20
412+
BOT_UpgradeSkill(ent, PLAGUE, 10); // clvl 48
413+
BOT_UpgradeSkill(ent, POWER_REGEN, 4); // clvl 50: PCR is maxed
370414
}
371415

372416
void BOT_UpgradeWeapon(edict_t* ent, int weapID)
@@ -392,7 +436,7 @@ void BOT_UpgradeWeapon(edict_t* ent, int weapID)
392436
while (ent->myskills.weapon_points > 0)
393437
{
394438
max = ent->myskills.weapons[w].mods[i].soft_max;
395-
//gi.dprintf("soft max: %d level: %d\n", max, ent->myskills.weapons[weapon_index].mods[i].current_level);
439+
//gi.dprintf("soft max: %d level: %d\n", max, ent->myskills.weapons[w].mods[i].current_level);
396440
if (ent->myskills.weapons[w].mods[i].current_level < max)
397441
{
398442
ent->myskills.weapons[w].mods[i].current_level++;

0 commit comments

Comments
 (0)