Kod:
#include <amxmodx>
#include <cellarray>
#include <engine>
#include <fakemeta>
#include <hamsandwich>
#include <cstrike>
#include <xs>
#define PLUGIN "Peeping Tom"
#define AUTHOR "joaquimandrade"
#define VERSION "1.0"
#define FLAG_ADMIN ADMIN_KICK
const MaxPlayers = 33;
const Vector=3
const X=0
const Y=1
const Z=2
enum Individual
{
Spectated,
Viewed
}
enum OriginOffset
{
FrameSide,
FrameTop,
FrameBottom,
}
enum FramePoint
{
TopLeft,
TopRight,
BottomLeft,
BottomRight
}
new Float:OriginOffsets[OriginOffset] = {_:13.0,_:25.0,_:36.0}
new Float:ScaleMultiplier = 0.013;
new Float:ScaleLower = 0.005
new spriteClassName[] = "peeping_tom";
enum Teams
{
Terrorist,
CounterTerrorist
}
new SpritesPath[Teams][] = {"sprites/peeping_tom/t.spr","sprites/peeping_tom/ct.spr"}
new Teams:TeamIndexes[CsTeams] = {0,_:Terrorist,_:CounterTerrorist,0}
new bool:IsAdmin[MaxPlayers]
new SpectatorsCounter;
new SpectatingUser[MaxPlayers]
new SpectatorsUserCounter[MaxPlayers]
new bool:OnFirstPersonView[MaxPlayers]
new Array:SpritesBySpectated[MaxPlayers]
new Array:SpritesByViewed[MaxPlayers];
new Trie:SpritesSpectators;
new Float:SpriteThinkDelay = 0.01;
new ForwardAddToFullPack
new HamHook:HamPlayerKilled
new Float:SomeNonZeroValue = 1.0
public plugin_init()
{
register_plugin(PLUGIN, VERSION, AUTHOR)
register_event("TextMsg","specMode","b","2&#Spec_Mode")
register_event("StatusValue","specTarget","bd","1=2")
register_event("SpecHealth2","specTarget","bd")
register_event("HLTV", "newRound", "a", "1=0", "2=0")
register_think(spriteClassName,"spriteThink");
HamPlayerKilled = RegisterHam(Ham_Killed,"player","playerKilled");
DisableHamForward(HamPlayerKilled);
}
public addToFullPack(es, e, ent, host, hostflags, player, pSet)
{
new spriteArray[2];
spriteArray[0] = ent;
spriteArray[1] = 0;
new Trie:spectators;
if(TrieGetCell(SpritesSpectators,spriteArray,spectators))
{
new spectatorArray[2];
spectatorArray[0] = host;
spectatorArray[1] = 0;
if(!TrieKeyExists(spectators,spectatorArray))
{
set_es(es, ES_RenderFx,kRenderFxNone)
set_es(es, ES_RenderMode,kRenderTransAlpha)
set_es(es, ES_RenderAmt, 0)
}
}
}
public plugin_cfg()
{
SpritesSpectators = TrieCreate();
}
public spriteThink(sprite)
{
entity_set_float(sprite,EV_FL_nextthink, get_gametime() + SpriteThinkDelay);
new ID[Individual]
ID[Spectated] = entity_get_edict(sprite,EV_ENT_euser1);
ID[Viewed] = entity_get_edict(sprite,EV_ENT_euser2);
new Float:origin[Individual][Vector]
entity_get_vector(ID[Spectated],EV_VEC_origin,origin[Spectated])
entity_get_vector(ID[Viewed],EV_VEC_origin,origin[Viewed])
new Float:diff[Vector]
new Float:diffAngles[Vector]
xs_vec_sub(origin[Viewed],origin[Spectated],diff)
xs_vec_normalize(diff,diff)
vector_to_angle(diff,diffAngles)
diffAngles[0] = 360 - diffAngles[0];
new Float:framePoints[FramePoint][Vector]
calculateFramePoints(origin[Viewed],framePoints,diffAngles)
new Float:eyes[Vector]
xs_vec_add(eyes,origin[Spectated],eyes)
new Float:viewOfs[Vector]
entity_get_vector(ID[Spectated],EV_VEC_view_ofs,viewOfs);
xs_vec_add(eyes,viewOfs,eyes);
new Float:framePointsTraced[FramePoint][Vector]
if(traceEyesFrame(ID[Spectated],eyes,framePoints,framePointsTraced))
{
new FramePoint:closerFramePoint = findCloserFramePoint(eyes,framePointsTraced)
new Float:otherPointInThePlane[Vector]
new Float:anotherPointInThePlane[Vector]
new Float:sideVector[Vector]
new Float:topBottomVector[Vector]
angle_vector(diffAngles,ANGLEVECTOR_UP,topBottomVector)
angle_vector(diffAngles,ANGLEVECTOR_RIGHT,sideVector)
xs_vec_mul_scalar(sideVector,SomeNonZeroValue,otherPointInThePlane)
xs_vec_mul_scalar(topBottomVector,SomeNonZeroValue,anotherPointInThePlane)
xs_vec_add(otherPointInThePlane,framePointsTraced[closerFramePoint],otherPointInThePlane)
xs_vec_add(anotherPointInThePlane,framePointsTraced[closerFramePoint],anotherPointInThePlane)
new Float:plane[4]
xs_plane_3p(plane,framePointsTraced[closerFramePoint],otherPointInThePlane,anotherPointInThePlane)
moveToPlane(plane,eyes,framePointsTraced);
new Float:upperMiddle[Vector]
new Float:lowerMiddle[Vector]
new Float:middle[Vector]
new Float:half = 2.0
xs_vec_add(framePointsTraced[TopLeft],framePointsTraced[TopRight],upperMiddle)
xs_vec_div_scalar(upperMiddle,half,upperMiddle)
xs_vec_add(framePointsTraced[BottomLeft],framePointsTraced[BottomRight],lowerMiddle)
xs_vec_div_scalar(lowerMiddle,half,lowerMiddle)
xs_vec_add(lowerMiddle,upperMiddle,middle)
xs_vec_div_scalar(middle,half,middle)
new Float:scale = ScaleMultiplier * vector_distance(framePointsTraced[TopLeft],framePointsTraced[TopRight])
if(scale < ScaleLower)
scale = ScaleLower;
entity_set_float(sprite,EV_FL_scale,scale);
entity_set_vector(sprite,EV_VEC_angles,diffAngles);
entity_set_origin(sprite,middle)
}
else
{
entity_set_origin(sprite,Float:{-1000.0,-1000.0,-1000.0});
}
}
public playerKilled(id, idattacker, shouldgib)
{
deleteSpritesByViewed(id);
}
createSpriteSpectatorsHolder(sprite)
{
new spriteArray[2];
spriteArray[0] = sprite;
spriteArray[1] = 0;
TrieSetCell(SpritesSpectators,spriteArray,TrieCreate());
}
deleteSpriteIfExists(sprite)
{
new spriteArray[2];
spriteArray[0] = sprite;
spriteArray[1] = 0;
if(TrieKeyExists(SpritesSpectators,spriteArray))
{
remove_entity(sprite);
deleteSpriteSpectatorsHolder(sprite);
}
}
deleteSpriteSpectatorsHolder(sprite)
{
new spriteArray[2];
spriteArray[0] = sprite;
spriteArray[1] = 0;
new Trie:spectators
TrieGetCell(SpritesSpectators,spriteArray,spectators);
TrieDestroy(spectators);
TrieDeleteKey(SpritesSpectators,spriteArray);
}
setSpriteSpectatorStatus(sprite,spectator,bool:status)
{
new spriteArray[2];
spriteArray[0] = sprite;
spriteArray[1] = 0;
if(TrieKeyExists(SpritesSpectators,spriteArray))
{
new Trie:spectators;
TrieGetCell(SpritesSpectators,spriteArray,spectators)
new spectatorArray[2];
spectatorArray[0] = spectator;
spectatorArray[1] = 0;
if(status)
{
TrieSetCell(spectators,spectatorArray,true);
}
else
{
TrieDeleteKey(spectators,spectatorArray);
}
}
}
public newRound()
{
new id,players[32],playerCount
get_players(players, playerCount, "")
for(new i=0;i<playerCount;i++)
{
id = players[i];
if((cs_get_user_team(id) == CS_TEAM_SPECTATOR) && OnFirstPersonView[id])
{
quitingFirstPersonView(id);
new params[1];
params[0] = id;
set_task(3.0,"taskJoinFirstPersonView",0,params,1);
}
else
{
checkQuitingFirstPersonView(id)
deleteSpritesByViewed(id);
}
}
}
public taskJoinFirstPersonView(params[])
{
joiningFirstPersonView(params[0]);
}
public client_authorized(id)
{
IsAdmin[id] = bool:(get_user_flags(id) & FLAG_ADMIN);
SpritesByViewed[id] = ArrayCreate();
SpectatingUser[id] = 0;
SpectatorsUserCounter[id] = 0
}
public client_disconnect(id)
{
checkQuitingFirstPersonView(id)
deleteSpritesByViewed(id);
}
createSprite(spectated,viewed)
{
new sprite = create_entity("info_target")
assert is_valid_ent(sprite);
entity_set_string(sprite,EV_SZ_classname,spriteClassName);
entity_set_model(sprite,SpritesPath[TeamIndexes[cs_get_user_team(viewed)]]);
entity_set_edict(sprite,EV_ENT_euser1,spectated)
entity_set_edict(sprite,EV_ENT_euser2,viewed)
entity_set_float(sprite,EV_FL_nextthink, get_gametime() + SpriteThinkDelay);
return sprite;
}
createSprites(spectator,spectated)
{
new Array:spritesBySpectated = ArrayCreate();
new i, viewed,players[32],playerCount
get_players(players, playerCount, "")
for (i=0; i<playerCount; i++)
{
viewed = players[i];
if(is_user_alive(viewed) && (viewed != spectated))
{
new sprite = createSprite(spectated,viewed);
createSpriteSpectatorsHolder(sprite);
setSpriteSpectatorStatus(sprite,spectator,true);
ArrayPushCell(spritesBySpectated,sprite);
ArrayPushCell(SpritesByViewed[viewed],sprite);
}
}
SpritesBySpectated[spectated] = spritesBySpectated;
}
deleteSprites(Array:sprites)
{
new nSprites = ArraySize(sprites);
for(new i=0;i<nSprites;i++)
{
new sprite = ArrayGetCell(sprites,i);
deleteSpriteIfExists(sprite)
}
ArrayDestroy(sprites);
}
deleteSpritesBySpectated(spectated)
{
deleteSprites(SpritesBySpectated[spectated]);
}
deleteSpritesByViewed(viewed)
{
deleteSprites(SpritesByViewed[viewed]);
SpritesByViewed[viewed] = ArrayCreate();
}
setSpritesSpectatorStatus(Array:sprites,spectator,bool:status)
{
new nSprites = ArraySize(sprites);
for(new i=0;i<nSprites;i++)
{
new sprite = ArrayGetCell(sprites,i);
setSpriteSpectatorStatus(sprite,spectator,status);
}
}
joiningFirstPersonView(id)
{
if(!SpectatorsCounter++)
{
ForwardAddToFullPack = register_forward(FM_AddToFullPack,"addToFullPack",1);
EnableHamForward(HamPlayerKilled);
}
OnFirstPersonView[id] = true;
new spectated = SpectatingUser[id]
if(!SpectatorsUserCounter[spectated]++)
{
createSprites(id,spectated);
}
else
{
setSpritesSpectatorStatus(SpritesBySpectated[spectated],id,true)
}
}
quitingFirstPersonView(id)
{
if(!--SpectatorsCounter)
{
unregister_forward(FM_AddToFullPack,ForwardAddToFullPack,1);
DisableHamForward(HamPlayerKilled);
}
OnFirstPersonView[id] = false;
new spectated = SpectatingUser[id]
if(!--SpectatorsUserCounter[spectated])
{
deleteSpritesBySpectated(spectated);
}
else
{
setSpritesSpectatorStatus(SpritesBySpectated[spectated],id,false)
}
}
checkQuitingFirstPersonView(id)
{
if(OnFirstPersonView[id])
{
quitingFirstPersonView(id);
}
}
public specMode(id)
{
if(IsAdmin[id])
{
new specMode[12]
read_data(2,specMode,11)
if((specMode[10] == '4') && SpectatingUser[id] && !OnFirstPersonView[id])
{
joiningFirstPersonView(id)
}
else
{
checkQuitingFirstPersonView(id);
}
}
}
public specTarget(id)
{
if(IsAdmin[id])
{
new spectated = read_data(2);
if(spectated)
{
if(OnFirstPersonView[id])
{
if(spectated != SpectatingUser[id])
{
quitingFirstPersonView(id);
SpectatingUser[id] = spectated;
joiningFirstPersonView(id)
}
}
SpectatingUser[id] = spectated;
}
}
}
public plugin_precache()
{
for(new Teams:i = Terrorist;i < Teams;i++)
precache_model(SpritesPath[i])
}
equalVectors(Float:vector1[Vector],Float:vector2[Vector])
{
for(new i=X;i<=Z;i++)
if(vector1[i] != vector2[i])
return false;
return true;
}
calculateFramePoints(Float:origin[Vector],Float:framePoints[FramePoint][Vector],Float:perpendicularAngles[Vector])
{
new Float:sideVector[Vector]
new Float:topBottomVector[Vector]
angle_vector(perpendicularAngles,ANGLEVECTOR_UP,topBottomVector)
angle_vector(perpendicularAngles,ANGLEVECTOR_RIGHT,sideVector)
new Float:sideDislocation[Vector]
new Float:bottomDislocation[Vector]
new Float:topDislocation[Vector]
xs_vec_mul_scalar(sideVector,Float:OriginOffsets[FrameSide],sideDislocation)
xs_vec_mul_scalar(topBottomVector,Float:OriginOffsets[FrameTop],topDislocation)
xs_vec_mul_scalar(topBottomVector,Float:OriginOffsets[FrameBottom],bottomDislocation)
xs_vec_add(framePoints[TopLeft],topDislocation,framePoints[TopLeft])
xs_vec_add(framePoints[TopLeft],sideDislocation,framePoints[TopRight])
xs_vec_sub(framePoints[TopLeft],sideDislocation,framePoints[TopLeft])
xs_vec_sub(framePoints[BottomLeft],bottomDislocation,framePoints[BottomLeft])
xs_vec_add(framePoints[BottomLeft],sideDislocation,framePoints[BottomRight])
xs_vec_sub(framePoints[BottomLeft],sideDislocation,framePoints[BottomLeft])
for(new FramePoint:i = TopLeft; i <= BottomRight; i++)
xs_vec_add(origin,framePoints[i],framePoints[i])
}
traceEyesFrame(id,Float:eyes[Vector],Float:framePoints[FramePoint][Vector],Float:framePointsTraced[FramePoint][Vector])
{
for(new FramePoint:i = TopLeft; i <= BottomRight; i++)
{
trace_line(id,eyes,framePoints[i],framePointsTraced[i])
if(equalVectors(framePoints[i],framePointsTraced[i]))
{
return false;
}
}
return true;
}
FramePoint:findCloserFramePoint(Float:eyes[Vector],Float:framePointsTraced[FramePoint][Vector])
{
new Float:closerDistance = vector_distance(eyes,framePointsTraced[TopLeft])
new FramePoint:closerFramePoint = TopLeft
for(new FramePoint:i=TopRight; i<=BottomRight; i++)
{
new Float:distance = vector_distance(eyes,framePointsTraced[i])
if(distance < closerDistance)
{
closerDistance = distance
closerFramePoint = i;
}
}
return closerFramePoint;
}
moveToPlane(Float:plane[4],Float:eyes[Vector],Float:framePointsTraced[FramePoint][Vector])
{
new Float:direction[Vector]
for(new FramePoint:i=TopLeft;i<=BottomRight;i++)
{
xs_vec_sub(eyes,framePointsTraced[i],direction)
xs_vec_normalize(direction,direction)
xs_plane_rayintersect(plane,framePointsTraced[i],direction,framePointsTraced[i])
}
})

