void Cmd_CreateSupplyStation_f (edict_t *ent) { edict_t *depot; vec3_t start; int talentLevel, cost=STATION_COST; float skill_mult=1.0, cost_mult=1.0, delay_mult=1.0;//Talent: Rapid Assembly & Precision Tuning if (debuginfo->value) gi.dprintf("%s just called Cmd_CreateSupplyStation_f\n", ent->client->pers.netname); if (ent->supplystation) { depot_remove(ent->supplystation, ent, true); return; } if(ent->myskills.abilities[SUPPLY_STATION].disable) return; //Talent: Rapid Assembly talentLevel = vrx_get_talent_level(ent, TALENT_RAPID_ASSEMBLY); if (talentLevel > 0) delay_mult -= 0.1 * talentLevel; //Talent: Precision Tuning else if ((talentLevel = vrx_get_talent_level(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[SUPPLY_STATION].current_level, cost)) return; //BuildSupplyStation(ent, cost, skill_mult, delay_mult); depot = BuildDepot(ent, skill_mult, delay_mult); if (!G_GetSpawnLocation(ent, 100, depot->mins, depot->maxs, start)) { safe_cprintf(ent, PRINT_HIGH, "Not enough room to spawn supply station.\n"); ent->supplystation = NULL; G_FreeEdict(depot); return; } VectorCopy(start, depot->s.origin); VectorCopy(ent->s.angles, depot->s.angles); depot->s.angles[PITCH] = 0; depot->s.angles[ROLL] = 0; gi.linkentity(depot); ent->client->ability_delay = level.time + DEPOT_DELAY * delay_mult; ent->client->pers.inventory[power_cube_index] -= cost; ent->holdtime = level.time + DEPOT_BUILD_TIME * delay_mult; gi.sound(depot, CHAN_ITEM, gi.soundindex("weapons/repair.wav"), 1, ATTN_NORM, 0); }
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; }