void Bot_Pain(ServerEntity_t *ent, ServerEntity_t *other, EntityDamageType_t type) { char sound[MAX_QPATH]; Weapon_t *myweapon, *hisweapon; // Let the player know how we're feeling. Bot_BroadcastMessage(ent,other); // Get both mine and our enemies weapon. myweapon = Weapon_GetCurrentWeapon(ent); hisweapon = Weapon_GetCurrentWeapon(other); if(!myweapon || (!Weapon_CheckPrimaryAmmo(myweapon,ent) && myweapon->primary_type != AM_MELEE)) { AI_SetThink(ent, AI_THINK_FLEEING); return; } // Otherwise check what we can see our enemy having (don't check ammo since it's unrealistic). else if(!hisweapon || hisweapon->primary_type == AM_MELEE) { // We see you! if(Monster_IsVisible(ent,other)) { AI_SetThink(ent, AI_THINK_ATTACKING); return; } } #if 0 // [16/7/2012] Moved to avoid a situation where we try fleeing without a target ~hogsy if( (ent->v.enemy && other->v.health > ent->v.enemy->v.health) || !ent->v.enemy) // [15/7/2012] Reckless but change our target to this new enemy ~hogsy ent->v.enemy = other; mywep = Weapon_GetCurrentWeapon(ent); hisweapon = Weapon_GetCurrentWeapon(other); // [15/7/2012] Check that I have a weapon and ammo ~hogsy if(!mywep || ent->v.currentammo <= 0) { // [15/7/2012] I don't! Find the closest waypoint to move back to a little ~hogsy point = Waypoint_GetByVisibility(ent->v.origin); POINTCHECK: if(!point) return; if( point->type == WAYPOINT_WEAPON || point->type == WAYPOINT_COVER || point->type == WAYPOINT_TYPE_DEFAULT) { AI_SetThink(ent,MONSTER); // [15/7/2012] Set the position we'll move to next ~hogsy Math_VectorCopy(ent->Monster.target,point->position); } else { // [15/7/2012] Keep on checking until we get something ~hogsy if(pointchecks >= 5) { // [15/7/2012] Didn't get anything... ~hogsy return; } pointchecks++; point = Waypoint_GetByVisibility(point->position); goto POINTCHECK; } return; } // [15/7/2012] Okay, he doesn't have a weapon ~hogsy else if(!hisweapon) // [15/7/2012] Since it's probably not even a player ~hogsy return; #endif #ifdef GAME_OPENKATANA switch(ent->local.style) { case BOT_COMPANION: if(ent->v.watertype == BSP_CONTENTS_WATER && ent->v.waterlevel == 3) { } else sprintf(sound,"player/mikiko/mikikodeath%i.wav",rand()%5+1); break; default: #endif if(ent->v.watertype == BSP_CONTENTS_WATER && ent->v.waterlevel == 3) { if(rand()%2 == 1) sprintf(sound,"player/playerchoke1.wav"); else sprintf(sound,"player/playerchoke3.wav"); } else sprintf(sound,"player/playerpain%i.wav",rand()%4+1); #ifdef GAME_OPENKATANA } #endif Sound(ent,CHAN_VOICE,sound,255,ATTN_NORM); }
void Bot_Think(edict_t *eBot) { // If the bot isn't dead, then add animations. if(eBot->monster.iState != STATE_DEAD) { if(eBot->v.flags & FL_ONGROUND) { if(( (eBot->v.velocity[0] < -4.0f || eBot->v.velocity[0] > 4.0f) || (eBot->v.velocity[1] < -4.0f || eBot->v.velocity[1] > 4.0f)) && (!eBot->local.dAnimationTime || eBot->local.iAnimationEnd == 9)) Entity_Animate(eBot,PlayerAnimation_Walk); else if((eBot->v.velocity[0] == 0 || eBot->v.velocity[1] == 0) && (!eBot->local.dAnimationTime || eBot->local.iAnimationEnd > 9)) { #ifdef GAME_OPENKATANA if(eBot->v.iActiveWeapon == WEAPON_DAIKATANA) Entity_Animate(eBot,PlayerAnimation_KatanaIdle); else #endif Entity_Animate(eBot,PlayerAnimation_Idle); } } } switch(eBot->monster.iThink) { case THINK_IDLE: #if 1 // Add some random movement. ~hogsy if(rand()%120 == 0) { int iResult = rand()%3; if(iResult == 0) eBot->v.velocity[0] += BOT_MIN_SPEED; else if(iResult == 1) eBot->v.velocity[0] -= BOT_MIN_SPEED; iResult = rand()%3; if(iResult == 0) eBot->v.velocity[1] += BOT_MIN_SPEED; else if(iResult == 1) eBot->v.velocity[1] -= BOT_MIN_SPEED; eBot->v.angles[1] = Math_VectorToYaw(eBot->v.velocity); } else if(rand()%150 == 0) { Monster_Jump(eBot,200.0f); Entity_Animate(eBot,PlayerAnimation_Jump); } #endif break; case THINK_WANDERING: { edict_t *eTarget; Waypoint_t *wPoint; // Weapon_t *wMyWeapon; // vec3_t vAngle; eTarget = Monster_GetTarget(eBot); if(eTarget) { if(Monster_GetRelationship(eBot,eTarget) == RELATIONSHIP_HATE) { // [22/3/2013] Begin attacking next frame ~hogsy Monster_SetThink(eBot,THINK_ATTACKING); return; } } if(!eBot->monster.vTarget) { // [28/7/2012] TODO: Find specific waypoint such as an item ~hogsy wPoint = Waypoint_GetByVisibility(eBot->v.origin); if(wPoint) { if(wPoint->bOpen) { // [22/3/2013] TODO: Tell that current entity it's time to move... ~hogsy } Math_VectorCopy(wPoint->position,eBot->monster.vTarget); } } #if 0 wMyWeapon = Weapon_GetCurrentWeapon(eBot); if(MONSTER_GetRange(eBot,eBot->v.enemy->v.origin) > 4000) return; else if(wMyWeapon->iPrimaryType == AM_MELEE && MONSTER_GetRange(eBot,eBot->v.enemy->v.origin) > MONSTER_RANGE_MELEE) return; else if(Monster_IsVisible(eBot,eBot->v.enemy)) { // [5/8/2012] No ammo and it's not a melee weapon? ~hogsy if(!Weapon_CheckPrimaryAmmo(eBot) && wMyWeapon->iPrimaryType != AM_MELEE) { // [5/8/2012] Should probably flee ~hogsy Monster_SetThink(eBot,THINK_FLEEING); return; } Math_VectorSubtract(eBot->v.enemy->v.origin,eBot->v.origin,vAngle); // ent->v.ideal_yaw = VectorToAngles(vAngle); ChangeYaw(eBot); } #endif } break; } }
void Bot_Pain(edict_t *ent,edict_t *other) { char sound[MAX_QPATH]; Weapon_t *wMyWeapon,*wHisWeapon; // [4/10/2012] Let the player know how we're feeling :) ~hogsy Bot_BroadcastMessage(ent,other); // [14/9/2012] Get both mine and our enemies weapon ~hogsy wMyWeapon = Weapon_GetCurrentWeapon(ent); wHisWeapon = Weapon_GetCurrentWeapon(other); if(!wMyWeapon || (!Weapon_CheckPrimaryAmmo(wMyWeapon,ent) && wMyWeapon->iPrimaryType != AM_MELEE)) { Monster_SetThink(ent,THINK_FLEEING); return; } // [14/9/2012] Otherwise check what we can see our enemy having (don't check ammo since it's unrealistic) ~hogsy else if(!wHisWeapon || wHisWeapon->iPrimaryType == AM_MELEE) { // [14/9/2012] We see you!! ~hogsy if(Monster_IsVisible(ent,other)) { Monster_SetEnemy(other); Monster_SetThink(ent,THINK_ATTACKING); return; } } #if 0 // [16/7/2012] Moved to avoid a situation where we try fleeing without a target ~hogsy if( (ent->v.enemy && other->v.iHealth > ent->v.enemy->v.iHealth) || !ent->v.enemy) // [15/7/2012] Reckless but change our target to this new enemy ~hogsy ent->v.enemy = other; mywep = Weapon_GetCurrentWeapon(ent); wHisWeapon = Weapon_GetCurrentWeapon(other); // [15/7/2012] Check that I have a weapon and ammo ~hogsy if(!mywep || ent->v.currentammo <= 0) { // [15/7/2012] I don't! Find the closest waypoint to move back to a little ~hogsy point = Waypoint_GetByVisibility(ent->v.origin); POINTCHECK: if(!point) return; if( point->type == WAYPOINT_WEAPON || point->type == WAYPOINT_COVER || point->type == WAYPOINT_DEFAULT) { Monster_SetThink(ent,MONSTER); // [15/7/2012] Set the position we'll move to next ~hogsy Math_VectorCopy(ent->monster.target,point->position); } else { // [15/7/2012] Keep on checking until we get something ~hogsy if(pointchecks >= 5) { // [15/7/2012] Didn't get anything... ~hogsy return; } pointchecks++; point = Waypoint_GetByVisibility(point->position); goto POINTCHECK; } return; } // [15/7/2012] Okay, he doesn't have a weapon ~hogsy else if(!wHisWeapon) // [15/7/2012] Since it's probably not even a player ~hogsy return; #endif #ifdef OPENKATANA // [26/7/2012] Character-based sounds ~hogsy // [29/7/2012] Revised ~hogsy switch(ent->local.style) { case BOT_MIKIKO: if(ent->v.watertype == BSP_CONTENTS_WATER && ent->v.waterlevel == 3) { } else sprintf(sound,"player/mikiko/mikikodeath%i.wav",rand()%5+1); break; case BOT_SUPERFLY: if(ent->v.watertype == BSP_CONTENTS_WATER && ent->v.waterlevel == 3) { } else sprintf(sound,"player/superfly/superflydeath%i.wav",rand()%4+1); break; default: #endif if(ent->v.watertype == BSP_CONTENTS_WATER && ent->v.waterlevel == 3) { if(rand()%2 == 1) sprintf(sound,"player/playerchoke1.wav"); else sprintf(sound,"player/playerchoke3.wav"); } else sprintf(sound,"player/playerpain%i.wav",rand()%4+1); #ifdef OPENKATANA } #endif Sound(ent,CHAN_VOICE,sound,255,ATTN_NORM); }
void Waypoint_Spawn(MathVector3f_t vOrigin,WaypointType_t type) { #ifdef DEBUG_WAYPOINT char *cModelName = WAYPOINT_MODEL_BASE; #endif int iPointContents; Waypoint_t *wPoint; /* TODO If we're between two other waypoints and they can be seen then slot ourselves in so that we act as the last waypoint instead. */ iPointContents = Engine.Server_PointContents(vOrigin); // [17/6/2012] Check that this area is safe ~hogsy if(iPointContents == BSP_CONTENTS_SOLID) { Engine.Con_Warning("Failed to place waypoint, position is within a solid!\n"); return; } { Waypoint_t *wVisibleWaypoint = Waypoint_GetByVisibility(vOrigin); // [30/1/2013] Oops! Check we actually have a visible waypoint!! ~hogsy if(wVisibleWaypoint) { MathVector3f_t vDistance; Math_VectorSubtract(wVisibleWaypoint->position,vOrigin,vDistance); if(Math_VectorLength(vDistance) < MONSTER_RANGE_MEDIUM) { Engine.Con_Printf("Invalid waypoint position!\n"); return; } } } wPoint = Waypoint_Allocate(); if(!wPoint) { Engine.Con_Warning("Failed to allocate waypoint!\n"); return; } Math_VectorCopy(vOrigin,wPoint->position); wPoint->number = waypoint_count; wPoint->bOpen = false; wPoint->next = Waypoint_GetByNumber(wPoint->number+1); wPoint->last = Waypoint_GetByNumber(wPoint->number-1); wPoint->wType = type; switch(type) { case WAYPOINT_ITEM: wPoint->cName = "item"; #ifdef DEBUG_WAYPOINT cModelName = WAYPOINT_MODEL_ITEM; #endif break; case WAYPOINT_CLIMB: wPoint->cName = "climb"; // TODO: Check that there's a ladder nearby. #ifdef DEBUG_WAYPOINT cModelName = WAYPOINT_MODEL_CLIMB; #endif break; case WAYPOINT_COVER: wPoint->cName = "cover"; // [27/12/2012] TODO: Check that this is actually cover ~hogsy break; case WAYPOINT_TYPE_JUMP: wPoint->cName = "jump"; // [27/12/2012] TODO: Check if this is actually a jump by tracing out ahead ~hogsy #ifdef DEBUG_WAYPOINT cModelName = WAYPOINT_MODEL_JUMP; #endif break; case WAYPOINT_TYPE_SWIM: if(iPointContents != BSP_CONTENTS_WATER) { Engine.Con_Warning("Waypoint with type swim not within water contents (%i %i %i)!", (int)vOrigin[0], (int)vOrigin[1], (int)vOrigin[2]); Waypoint_Delete(wPoint); return; } wPoint->cName = "swim"; #ifdef DEBUG_WAYPOINT cModelName = WAYPOINT_MODEL_SWIM; #endif break; case WAYPOINT_TYPE_DEFAULT: wPoint->cName = "default"; break; case WAYPOINT_SPAWN: wPoint->cName = "spawn"; break; default: Engine.Con_Warning("Unknown waypoint type (%i)!\n",type); Waypoint_Delete(wPoint); return; } // [30/1/2013] Pathetic reordering... Ugh ~hogsy if(!wPoint->last) { wPoint->last = Waypoint_GetByVisibility(vOrigin); if(!wPoint->last) { Engine.Con_Warning("Failed to get another visible waypoint! (%i)\n",wPoint->number); return; } } else if(wPoint->last != wPoint && wPoint->last->next) wPoint->last->next = wPoint; #ifdef DEBUG_WAYPOINT wPoint->eDebug = Entity_Spawn(); if(wPoint->eDebug) { wPoint->eDebug->v.effects = EF_MOTION_ROTATE; Entity_SetModel(wPoint->eDebug,cModelName); Entity_SetSizeVector(wPoint->eDebug,g_mvOrigin3f,g_mvOrigin3f); Entity_SetOrigin(wPoint->eDebug,wPoint->position); } Engine.Con_DPrintf("Waypoint placed (%i %i %i)\n", (int)wPoint->position[0], (int)wPoint->position[1], (int)wPoint->position[2]); Engine.Con_DPrintf(" number: %i\n",wPoint->number); Engine.Con_DPrintf(" type: %i\n",wPoint->wType); #endif }