void Cmd_BuildLaser (edict_t *ent) { int talentLevel, cost=LASER_COST; float skill_mult=1.0, cost_mult=1.0, delay_mult=1.0;//Talent: Rapid Assembly & Precision Tuning if(ent->myskills.abilities[BUILD_LASER].disable) return; if (Q_strcasecmp (gi.args(), "remove") == 0) { RemoveLasers(ent); gi.cprintf(ent, PRINT_HIGH, "All lasers removed.\n"); return; } // cost is doubled if you are a flyer or cacodemon below skill level 5 if ((ent->mtype == MORPH_FLYER && ent->myskills.abilities[FLYER].current_level < 5) || (ent->mtype == MORPH_CACODEMON && ent->myskills.abilities[CACODEMON].current_level < 5)) cost *= 2; //Talent: Rapid Assembly talentLevel = getTalentLevel(ent, TALENT_RAPID_ASSEMBLY); if (talentLevel > 0) delay_mult -= 0.1 * talentLevel; //Talent: Precision Tuning else if ((talentLevel = getTalentLevel(ent, TALENT_PRECISION_TUNING)) > 0) { cost_mult += PRECISION_TUNING_COST_FACTOR * talentLevel; delay_mult += PRECISION_TUNING_DELAY_FACTOR * talentLevel; skill_mult += PRECISION_TUNING_SKILL_FACTOR * talentLevel; } cost *= cost_mult; if (!G_CanUseAbilities(ent, ent->myskills.abilities[BUILD_LASER].current_level, cost)) return; if (ent->num_lasers >= MAX_LASERS) { gi.cprintf(ent, PRINT_HIGH, "Can't build any more lasers.\n"); return; } if (ctf->value && (CTF_DistanceFromBase(ent, NULL, CTF_GetEnemyTeam(ent->teamnum)) < CTF_BASE_DEFEND_RANGE)) { gi.cprintf(ent, PRINT_HIGH, "Can't build in enemy base!\n"); return; } SpawnLaser(ent, cost, skill_mult, delay_mult); }
void SpawnTotem(edict_t *ent, int abilityID) { int talentLevel, cost=TOTEM_COST; edict_t *totem; int totemType; vec3_t start;//GHz 4.32 // cost is doubled if you are a flyer or cacodemon below skill level 5 if ((ent->mtype == MORPH_FLYER && ent->myskills.abilities[FLYER].current_level < 5) || (ent->mtype == MORPH_CACODEMON && ent->myskills.abilities[CACODEMON].current_level < 5)) cost *= 2; if(!V_CanUseAbilities(ent, abilityID, cost, true)) return; if (ctf->value && abilityID == FIRE_TOTEM && (CTF_DistanceFromBase(ent, NULL, CTF_GetEnemyTeam(ent->teamnum)) < CTF_BASE_DEFEND_RANGE)) { safe_cprintf(ent, PRINT_HIGH, "Can't build in enemy base!\n"); return; } //Determine the totem type. switch(abilityID) { case FIRE_TOTEM: totemType = TOTEM_FIRE; break; case WATER_TOTEM: totemType = TOTEM_WATER; break; case AIR_TOTEM: totemType = TOTEM_AIR; break; case EARTH_TOTEM: totemType = TOTEM_EARTH; break; case DARK_TOTEM: totemType = TOTEM_DARKNESS; break; case NATURE_TOTEM: totemType = TOTEM_NATURE; break; default: return; } //Can't create too many totems. if(ent->totem1) { //Can't have more than one totem without the talent. /*if(getTalentLevel(ent, TALENT_TOTEM) < 1) { safe_cprintf(ent, PRINT_HIGH, "You already have a totem active.\n"); return; } //Can't have more than two totems. else*/ if(ent->totem2) { safe_cprintf(ent, PRINT_HIGH, "You already have two totems active.\n"); return; } //Can't have two totems of opposite alignment. else { int opposite = 0; switch(ent->totem1->mtype) { case TOTEM_FIRE: opposite = TOTEM_WATER; break; case TOTEM_WATER: opposite = TOTEM_FIRE; break; case TOTEM_AIR: opposite = TOTEM_EARTH; break; case TOTEM_EARTH: opposite = TOTEM_AIR; break; case TOTEM_DARKNESS: opposite = TOTEM_NATURE; break; case TOTEM_NATURE: opposite = TOTEM_DARKNESS; break; } if(totemType == opposite) { safe_cprintf(ent, PRINT_HIGH, "You can't create two totems of opposite elemental alignment.\n"); return; } else if(totemType == ent->totem1->mtype) { safe_cprintf(ent, PRINT_HIGH, "You can't create totems of the same type.\n"); return; } } } //Drop a totem. totem = DropTotem(ent); totem->mtype = totemType; totem->monsterinfo.level = ent->myskills.abilities[abilityID].current_level; totem->classname = "totem"; /*totem->owner =*/ totem->activator = ent; totem->think = totem_general_think; totem->touch = totem_touch; totem->nextthink = level.time + FRAMETIME*2; totem->delay = level.time + 0.5; totem->die = totem_die; //TODO: update this with the new model. totem->s.modelindex = gi.modelindex("models/items/mega_h/tris.md2"); //totem->s.angles[ROLL] = 270; VectorSet (totem->mins, -8, -8, -12); VectorSet (totem->maxs, 8, 8, 16); VectorCopy(ent->s.origin, totem->s.origin); totem->health = TOTEM_HEALTH_BASE + TOTEM_HEALTH_MULT * totem->monsterinfo.level; //Talent: Totemic Focus - increases totem health if((talentLevel = getTalentLevel(ent, TALENT_TOTEM)) > 0) totem->health *= 1 + 0.1666 * talentLevel; if (totemType == TOTEM_FIRE) { // fire totem is much tougher totem->health *= 2; // fire totem has a longer delay totem->delay = level.time + 2.0; } totem->max_health = totem->health*2; //Not sure if this stuff is needed (Archer) totem->svflags |= SVF_MONSTER; totem->takedamage = DAMAGE_AIM; totem->clipmask = MASK_MONSTERSOLID; //Back to stuff we need totem->mass = 200; totem->movetype = MOVETYPE_TOSS;//MOVETYPE_WALK; totem->deadflag = DEAD_NO; totem->svflags &= ~SVF_DEADMONSTER; totem->solid = SOLID_BBOX; //Graphical effects //TODO: update this to make it look better. totem->s.effects |= EF_PLASMA | EF_COLOR_SHELL | EF_SPHERETRANS; switch(totemType) { case TOTEM_FIRE: totem->s.effects |= 262144; //red radius light totem->s.renderfx |= RF_SHELL_RED; break; case TOTEM_WATER: totem->s.effects |= 524288; //blue radius light totem->s.renderfx |= RF_SHELL_CYAN; break; case TOTEM_AIR: totem->s.effects |= 64; //bright light radius totem->s.renderfx |= RF_SHELL_RED | RF_SHELL_BLUE | RF_SHELL_GREEN; break; case TOTEM_EARTH: totem->s.renderfx |= RF_SHELL_YELLOW; break; case TOTEM_DARKNESS: totem->s.effects |= 2147483648; //strange darkness effect //totem->s.renderfx |= RF_SHELL_RED | RF_SHELL_BLUE; break; case TOTEM_NATURE: totem->s.effects |= 128; //green radius light totem->s.renderfx |= RF_SHELL_GREEN; break; } //GHz 4.32 if (!G_GetSpawnLocation(ent, 64, totem->mins, totem->maxs, start)) { G_FreeEdict(totem); return; } VectorCopy(start, totem->s.origin); gi.linkentity(totem); //GHz if(!ent->totem1) ent->totem1 = totem; else ent->totem2 = totem; ent->client->pers.inventory[ITEM_INDEX(Fdi_POWERCUBE)] -= cost; // calling entity made a sound, used to alert monsters ent->lastsound = level.framenum; ent->client->ability_delay = level.time + 1.3; }
void Cmd_MiniSentry_f (edict_t *ent) { int talentLevel, sentries=0, cost=SENTRY_COST; float skill_mult=1.0, cost_mult=1.0, delay_mult=1.0;//Talent: Rapid Assembly & Precision Tuning edict_t *scan=NULL; if (debuginfo->value) gi.dprintf("%s just called Cmd_MiniSentry_f\n", ent->client->pers.netname); if (ent->myskills.abilities[BUILD_SENTRY].disable) return; if (!Q_strcasecmp(gi.args(), "remove")) { RemoveMiniSentries(ent); return; } // 3.9 double sentry cost if there are too many sentries in CTF if (ctf->value) { sentries += 2*CTF_GetNumSummonable("Sentry_Gun", ent->teamnum); sentries += CTF_GetNumSummonable("msentrygun", ent->teamnum); if (sentries > MAX_MINISENTRIES) cost *= 2; } // cost is doubled if you are a flyer or cacodemon below skill level 5 if ((ent->mtype == MORPH_FLYER && ent->myskills.abilities[FLYER].current_level < 5) || (ent->mtype == MORPH_CACODEMON && ent->myskills.abilities[CACODEMON].current_level < 5)) cost *= 2; //Talent: Rapid Assembly talentLevel = getTalentLevel(ent, TALENT_RAPID_ASSEMBLY); if (talentLevel > 0) delay_mult -= 0.1 * talentLevel; //Talent: Precision Tuning else if ((talentLevel = getTalentLevel(ent, TALENT_PRECISION_TUNING)) > 0) { cost_mult += PRECISION_TUNING_COST_FACTOR * talentLevel; delay_mult += PRECISION_TUNING_DELAY_FACTOR * talentLevel; skill_mult += PRECISION_TUNING_SKILL_FACTOR * talentLevel; } cost *= cost_mult; if (!G_CanUseAbilities(ent, ent->myskills.abilities[BUILD_SENTRY].current_level, cost)) return; if (ent->num_sentries >= MAX_MINISENTRIES) { safe_cprintf(ent, PRINT_HIGH, "You have reached the max of %d sentries\n", MAX_MINISENTRIES); return; } if (ctf->value && (CTF_DistanceFromBase(ent, NULL, CTF_GetEnemyTeam(ent->teamnum)) < CTF_BASE_DEFEND_RANGE)) { safe_cprintf(ent, PRINT_HIGH, "Can't build in enemy base!\n"); return; } SpawnMiniSentry(ent, cost, skill_mult, delay_mult); }