| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
 138
 139
 140
 141
 142
 143
 144
 145
 146
 147
 148
 149
 150
 151
 152
 153
 154
 155
 156
 157
 158
 159
 160
 161
 162
 163
 164
 165
 166
 167
 168
 169
 170
 171
 172
 173
 174
 175
 176
 177
 178
 179
 180
 181
 182
 183
 184
 185
 186
 187
 188
 189
 190
 191
 192
 193
 194
 195
 196
 197
 198
 199
 200
 201
 202
 203
 204
 205
 206
 207
 208
 209
 210
 211
 212
 213
 214
 215
 216
 217
 218
 219
 220
 221
 222
 223
 224
 225
 226
 227
 228
 229
 
 | /*
===========================================================================
Return to Castle Wolfenstein multiplayer GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company. 
This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (RTCW MP Source Code).  
RTCW MP 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 3 of the License, or
(at your option) any later version.
RTCW MP 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 RTCW MP Source Code.  If not, see <http://www.gnu.org/licenses/>.
In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code.  If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
//===========================================================================
//
// Name:			ai_cast_script_ents.c
// Function:		Wolfenstein AI Character Scripting
// Programmer:		Ridah
// Tab Size:		4 (real tabs)
//===========================================================================
#include "g_local.h"
#include "../qcommon/q_shared.h"
#include "../botlib/botlib.h"      //bot lib interface
#include "../botlib/be_aas.h"
#include "../botlib/be_ea.h"
#include "../botlib/be_ai_gen.h"
#include "../botlib/be_ai_goal.h"
#include "../botlib/be_ai_move.h"
#include "../botlib/botai.h"          //bot ai interface
#include "ai_cast.h"
/*QUAKED ai_marker (1 0.5 0) (-18 -18 -24) (18 18 48) NODROP
AI marker
NODROP means dont drop it to the ground
"targetname" : identifier for this marker
*/
/*
============
SP_ai_marker
============
*/
extern vec3_t playerMins, playerMaxs;
void SP_ai_marker( gentity_t *ent ) {
	vec3_t dest;
	trace_t tr;
	vec3_t checkMins, checkMaxs;
	if ( g_gametype.integer != GT_SINGLE_PLAYER ) {
		G_FreeEntity( ent );
		return;
	}
//----(SA)	move the bounding box for the check in 1 unit on each side so they can butt up against a wall and not startsolid
	VectorCopy( playerMins, checkMins );
	checkMins[0] += 1;
	checkMins[1] += 1;
	VectorCopy( playerMaxs, checkMaxs );
	checkMaxs[0] -= 1;
	checkMaxs[1] -= 1;
//----(SA)	end
	if ( !( ent->spawnflags & 1 ) ) {
		// drop to floor
		ent->r.currentOrigin[2] += 1.0; // fixes QErad -> engine bug?
		VectorSet( dest, ent->r.currentOrigin[0], ent->r.currentOrigin[1], ent->r.currentOrigin[2] - 4096 );
		trap_Trace( &tr, ent->r.currentOrigin, checkMins, checkMaxs, dest, ent->s.number, MASK_PLAYERSOLID );
		if ( tr.startsolid ) {
			G_Printf( "WARNING: ai_marker (%s) in solid at %s\n", ent->targetname, vtos( ent->r.currentOrigin ) );
			return;
		}
		G_SetOrigin( ent, tr.endpos );
	}
}
/*QUAKED ai_effect (0.3 0.8 0.2) (-4 -4 -4) (4 4 4)
AI effect entity
"ainame" is the name of the AI character that uses this entity for effects
*/
/*
============
SP_ai_effect
============
*/
void ai_effect_think( gentity_t *ent ) {
	gentity_t *targ;
	// find the client number that uses this entity
	targ = AICast_FindEntityForName( ent->aiName );
	if ( !targ ) {
		// keep waiting until they enter, if they never do, then we have no purpose, therefore no harm can be done
		ent->think = ai_effect_think;
		ent->nextthink = level.time + 200;
		return;
		//G_Error( "ai_effect with invalid aiName at %s\n", vtos(ent->s.origin) );
	}
	// make sure the clients can use this association
	ent->s.otherEntityNum = targ->s.number;
	ent->s.eType = ET_AI_EFFECT;
	G_SetOrigin( ent, ent->s.origin );
	trap_LinkEntity( ent );
	ent->r.svFlags |= SVF_BROADCAST;    // make sure all clients are aware of this entity
}
void SP_ai_effect( gentity_t *ent ) {
	if ( g_gametype.integer != GT_SINGLE_PLAYER ) {
		G_FreeEntity( ent );
		return;
	}
	ent->think = ai_effect_think;
	ent->nextthink = level.time + 500;
}
//===========================================================
// the wait time has passed, so set back up for another activation
void AICast_trigger_wait( gentity_t *ent ) {
	ent->nextthink = 0;
}
// the trigger was just activated
// ent->activator should be set to the activator so it can be held through a delay
// so wait for the delay time before firing
void AICast_trigger_trigger( gentity_t *ent, gentity_t *activator ) {
	if ( ent->nextthink ) {
		return;     // can't retrigger until the wait is over
	}
	ent->activator = AICast_FindEntityForName( ent->aiName );
	if ( ent->activator ) { // they might be dead
		// trigger the script event
		AICast_ScriptEvent( AICast_GetCastState( ent->activator->s.number ), "trigger", ent->target );
	}
	if ( ent->wait > 0 ) {
		ent->think = AICast_trigger_wait;
		ent->nextthink = level.time + ( ent->wait + ent->random * crandom() ) * 1000;
	} else {
		// we can't just remove (self) here, because this is a touch function
		// called while looping through area links...
		ent->touch = 0;
		ent->nextthink = level.time + FRAMETIME;
		ent->think = G_FreeEntity;
	}
}
void AICast_Touch_Trigger( gentity_t *self, gentity_t *other, trace_t *trace ) {
	if ( !other->client || ( other->r.svFlags & SVF_CASTAI ) ) {
		return;
	}
	AICast_trigger_trigger( self, other );
}
/*QUAKED ai_trigger (1 0.5 0) ? Startoff
Triggered only by the player touching it
"wait" : Seconds between triggerings, -1 = one time only (default).
"ainame" : name of AI to target (use "player" for the.. player)
"target" : trigger identifier for that AI script
*/
extern void InitTrigger( gentity_t *self );
void ai_trigger_activate( gentity_t *self ) {
	if ( self->r.linked ) {
		return;
	}
	self->use = 0;
	self->AIScript_AlertEntity = 0;
	self->touch = AICast_Touch_Trigger;
	InitTrigger( self );
	trap_LinkEntity( self );
}
void ai_trigger_use( gentity_t *self, gentity_t *other, gentity_t *activator ) {
	ai_trigger_activate( self );
}
void SP_ai_trigger( gentity_t *ent ) {
	if ( g_gametype.integer != GT_SINGLE_PLAYER ) {
		G_FreeEntity( ent );
		return;
	}
	G_SpawnFloat( "wait", "-1", &ent->wait );
	if ( !ent->aiName ) {
		G_Error( "ai_trigger without \"ainame\"\n" );
	}
	if ( !ent->target ) {
		G_Error( "ai_trigger without \"target\"\n" );
	}
	if ( ent->spawnflags & 1 ) { // TriggerSpawn
		ent->AIScript_AlertEntity = ai_trigger_activate;
		ent->use = ai_trigger_use;
		trap_UnlinkEntity( ent );
	} else {
		ai_trigger_activate( ent );
	}
}
 |