<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://bf2tech.uturista.pt/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Pireax</id>
	<title>BF2 Technical Information Wiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://bf2tech.uturista.pt/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Pireax"/>
	<link rel="alternate" type="text/html" href="https://bf2tech.uturista.pt/index.php/Special:Contributions/Pireax"/>
	<updated>2026-08-06T00:30:42Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.40.1</generator>
	<entry>
		<id>https://bf2tech.uturista.pt/index.php?title=BF2_Internals&amp;diff=156</id>
		<title>BF2 Internals</title>
		<link rel="alternate" type="text/html" href="https://bf2tech.uturista.pt/index.php?title=BF2_Internals&amp;diff=156"/>
		<updated>2019-01-26T23:05:54Z</updated>

		<summary type="html">&lt;p&gt;Pireax: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The BF2 engine has been written in C++ and also make heavy use of STL. &lt;br /&gt;
&lt;br /&gt;
{{tip}} All virtual functions on this page are in the order they are defined in the vtable unless otherwise specified.&lt;br /&gt;
&lt;br /&gt;
== Reference Counting ==&lt;br /&gt;
A lot of the internal components of the game use intrusive reference counting through inheritance.&lt;br /&gt;
The base class would look something like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class RefCounted {&lt;br /&gt;
public:&lt;br /&gt;
    RefCounted() : m_refCount(1) {}&lt;br /&gt;
&lt;br /&gt;
    virtual int addRef() {&lt;br /&gt;
        return ++m_refCount;&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    virtual int getRefCount() const {&lt;br /&gt;
        return m_refCount;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Unsure if there actually is a base implementation of this method,&lt;br /&gt;
    // this sometimes points to a unique function in the vtable but follows this pattern.&lt;br /&gt;
    virtual int release() {&lt;br /&gt;
        if (--m_refCount == 0) {&lt;br /&gt;
            delete (RefCounted*)this;&lt;br /&gt;
        }&lt;br /&gt;
        return m_refCount;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Position of the destructor in the vtable may change.&lt;br /&gt;
    virtual ~RefCounted() {}&lt;br /&gt;
private:&lt;br /&gt;
    int m_refCount;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Do note that this class is not thread-safe, as in the actual implementation.&lt;br /&gt;
&lt;br /&gt;
== ClassManager ==&lt;br /&gt;
The program contains a single ClassManager instance which is used to dynamically access different subsystems within the game.&lt;br /&gt;
These subsystems are registered via a string identifier(class name), an instance pointer, the class id and another unknown integer, they can then later be accessed using the class name.&lt;br /&gt;
The following classes are registered in BF2.exe:&lt;br /&gt;
; GameServerSettings&lt;br /&gt;
; HudInformationLayer&lt;br /&gt;
; DistributedLightRenderer&lt;br /&gt;
; LocalProfileManager&lt;br /&gt;
; ProfileManager&lt;br /&gt;
; RankManager&lt;br /&gt;
; ClanManager&lt;br /&gt;
; NewsManager&lt;br /&gt;
; AutoPatch&lt;br /&gt;
; Persistence&lt;br /&gt;
; MenuTeamManager&lt;br /&gt;
; GlobalSettings&lt;br /&gt;
; VideoSettings&lt;br /&gt;
; AudioSettings&lt;br /&gt;
; ControlSettings&lt;br /&gt;
; GeneralSettings&lt;br /&gt;
; HapticSettings&lt;br /&gt;
; ServerBrowserManager&lt;br /&gt;
; SwiffHost&lt;br /&gt;
; DemoLibrary&lt;br /&gt;
; ServerLogoManager&lt;br /&gt;
; ModInfo&lt;br /&gt;
&lt;br /&gt;
The rendering module(RendDX9.dll) also registers the following classes:&lt;br /&gt;
; SwiffRenderer&lt;br /&gt;
; Terrain&lt;br /&gt;
; LightManager&lt;br /&gt;
; GeometryTemplateManager&lt;br /&gt;
; StaticMeshRenderer&lt;br /&gt;
; SkinnedMeshRenderer&lt;br /&gt;
; ParticleSystemManager&lt;br /&gt;
; HemiMapManager&lt;br /&gt;
; DecalManager&lt;br /&gt;
; DecalShadowManager&lt;br /&gt;
; RoadCompiledRenderer&lt;br /&gt;
; RoadEditableRenderer&lt;br /&gt;
; NametagManager&lt;br /&gt;
; SkyDome&lt;br /&gt;
; UndergrowthSystem&lt;br /&gt;
; LightingManager&lt;br /&gt;
; WeatherManager&lt;br /&gt;
; RainManager&lt;br /&gt;
; RenderView&lt;br /&gt;
; EnvMapManager&lt;br /&gt;
&lt;br /&gt;
== Common ==&lt;br /&gt;
=== GameEvent ===&lt;br /&gt;
The game has multiple event systems, game events are events that occur in-game and are related to gameplay.&lt;br /&gt;
The (incomplete) class below is the base class used by all events, events often have additional data.&lt;br /&gt;
A GameEvent has a maximum size of 1024 bits as defined by &amp;lt;code&amp;gt;const uint MaximumGameEventSize&amp;lt;/code&amp;gt;.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class GameEvent : public RefCounted {&lt;br /&gt;
public:&lt;br /&gt;
    GameEvent() : field_8(-1) {}&lt;br /&gt;
    &lt;br /&gt;
    // multiple virtual functions here&lt;br /&gt;
private:&lt;br /&gt;
    int field_8;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
List of Game events:&lt;br /&gt;
; ChallengeEvent&lt;br /&gt;
; ChallengeResponseEvent&lt;br /&gt;
; ConnectionTypeEvent&lt;br /&gt;
; DataBlockEvent&lt;br /&gt;
; CreatePlayerEvent&lt;br /&gt;
; CreateObjectEvent&lt;br /&gt;
; CreateKitEvent&lt;br /&gt;
; DestroyObjectEvent&lt;br /&gt;
; DestroyPlayerEvent&lt;br /&gt;
; EnterVehicleEvent&lt;br /&gt;
; ExitVehicleEvent&lt;br /&gt;
; PostRemoteEvent&lt;br /&gt;
; ChangePlayerNameEvent&lt;br /&gt;
; HandlePickupEvent&lt;br /&gt;
; HandleDropEvent&lt;br /&gt;
; StringBlockEvent&lt;br /&gt;
; JoinSquadEvent&lt;br /&gt;
; LeaveSquadEvent&lt;br /&gt;
; CommanderEvent&lt;br /&gt;
; RadioMessageEvent&lt;br /&gt;
; KilledByEvent&lt;br /&gt;
; ChangeSquadNameEvent&lt;br /&gt;
; SetPrivateSquadEvent&lt;br /&gt;
; IssueSquadOrderEvent&lt;br /&gt;
; InviteEvent&lt;br /&gt;
; RankEvent&lt;br /&gt;
; KickBanEvent&lt;br /&gt;
; SetAcceptOrderEvent&lt;br /&gt;
; SetSquadLeaderEvent&lt;br /&gt;
; SpottedEvent&lt;br /&gt;
; ArtilleryEvent&lt;br /&gt;
; StickyProjectileEvent&lt;br /&gt;
; AmbientEffectAreaEvent&lt;br /&gt;
; VoipOnOffEvent&lt;br /&gt;
; CommanderCamEvent&lt;br /&gt;
; SupplyDropEvent&lt;br /&gt;
; VoidPlayerMuteEvent&lt;br /&gt;
; VoteEvent&lt;br /&gt;
; TargetDirectionEvent&lt;br /&gt;
; BeginRoundEvent&lt;br /&gt;
; EndOfRoundEvent&lt;br /&gt;
; PythonCommandEvent&lt;br /&gt;
; RequestEvent&lt;br /&gt;
; VoipSessionEvent&lt;br /&gt;
; ToggleFreeCameraEvent&lt;br /&gt;
; MedalEvent&lt;br /&gt;
; UnlockEvent&lt;br /&gt;
; MissileInitEvent&lt;br /&gt;
; UAVEvent&lt;br /&gt;
; ContentCheckEvent&lt;br /&gt;
; DropVehicleEvent&lt;br /&gt;
; CreateSpawnGroupEvent&lt;br /&gt;
; RemoveSpawnGroupEvent&lt;br /&gt;
; UpdateTriggerEvent&lt;br /&gt;
; GrapplingHookContainerCreateEvent&lt;br /&gt;
; GrapplingHookContainerUpdateEvent&lt;br /&gt;
; GrapplingHookContainerDetachEvent&lt;br /&gt;
; GrapplingHookCreateEvent&lt;br /&gt;
; GrapplingHookUpdateEvent&lt;br /&gt;
; PlayerTearGassedEvent&lt;br /&gt;
; SetNightVisionEvent&lt;br /&gt;
; VerifyPlayerTeamEvent&lt;br /&gt;
; FixPlayerTeamEvent&lt;br /&gt;
&lt;br /&gt;
== IO ==&lt;br /&gt;
Access to the filesystem is done through the FileManager accessible through the ClassManager.&lt;br /&gt;
&lt;br /&gt;
=== Stream ===&lt;br /&gt;
Interface used for files, used by FileManager.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Stream {&lt;br /&gt;
public:&lt;br /&gt;
    virtual unsigned read(void* buffer, unsigned numBytes) = 0;&lt;br /&gt;
    virtual bool write(void* buffer, unsigned numBytes) = 0;&lt;br /&gt;
    virtual int unk_1() {};&lt;br /&gt;
    virtual int unk_2() {};&lt;br /&gt;
    virtual Stream clone() = 0;&lt;br /&gt;
    virtual int unk_3() {};&lt;br /&gt;
    virtual int unk_4() {};&lt;br /&gt;
    virtual int unk_5() {};&lt;br /&gt;
    virtual bool seek(unsigned moveMethod, long distanceToMove) = 0;&lt;br /&gt;
    virtual unsigned getPosition() = 0;&lt;br /&gt;
    virtual unsigned getSize() = 0;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== FileSystem ===&lt;br /&gt;
Interface used and implemented by the FileManager to access the underlying file system.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class FileSystem {&lt;br /&gt;
public:&lt;br /&gt;
    virtual int unk_1() {}&lt;br /&gt;
    virtual int unk_2() {}&lt;br /&gt;
    virtual Stream* openFile(std::string* path) = 0;&lt;br /&gt;
    virtual int unk_3() {}&lt;br /&gt;
    virtual int unk_4() {}&lt;br /&gt;
    virtual int unk_5() {}&lt;br /&gt;
    virtual int unk_6() {}&lt;br /&gt;
    virtual bool readFile(std::string* path, void* buffer, unsigned numBytes, unsigned* bytesRed) = 0;&lt;br /&gt;
    virtual int unk_7() {}&lt;br /&gt;
    virtual int findFiles(std::string* folderPath, ? a, ? b) = 0;&lt;br /&gt;
    virtual int getFileInfo(std::string* path, ? a) = 0;&lt;br /&gt;
    virtual int compareFileTime(std::string* path, std::string* otherPath) = 0;&lt;br /&gt;
    virtual bool getFullFileName(std::string* path) = 0;&lt;br /&gt;
    virtual void update() = 0;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Pireax</name></author>
	</entry>
	<entry>
		<id>https://bf2tech.uturista.pt/index.php?title=File_Formats&amp;diff=155</id>
		<title>File Formats</title>
		<link rel="alternate" type="text/html" href="https://bf2tech.uturista.pt/index.php?title=File_Formats&amp;diff=155"/>
		<updated>2018-12-29T21:33:13Z</updated>

		<summary type="html">&lt;p&gt;Pireax: /* terraindata.raw */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== Image Files ===&lt;br /&gt;
The majority of the image files within the Battlefield 2 directory structure have the &#039;&#039;&#039;PNG&#039;&#039;&#039; file extension, however most of these image files are in fact &#039;&#039;&#039;DDS&#039;&#039;&#039; files with an incorrect file extension. There are a few image files that really are PNG files (mainly within &amp;lt;tt&amp;gt;Battlefield 2\mods\bf2\Objects\&amp;lt;/tt&amp;gt;), and can be easily loaded by an image viewer/editor.&lt;br /&gt;
&lt;br /&gt;
The image files in Menu_client.zip are packed into a DDS Texture Atlas file. Basicly, an atlas file combines a lot of small images into one big image to improve reading performance. An index file with coordinates is used to locate the individual images in the Atlas.&lt;br /&gt;
The Atlas images and index files are located in Menu_client.zip/Atlas.&lt;br /&gt;
&lt;br /&gt;
=== Basic File Format Data Types ===&lt;br /&gt;
==== String ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct String {&lt;br /&gt;
    uint len;&lt;br /&gt;
    char cstr[len];&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Vec2 ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
struct Vec2 {&lt;br /&gt;
    float x;&lt;br /&gt;
    float y;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Vec3 ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
struct Vec3 {&lt;br /&gt;
    float x;&lt;br /&gt;
    float y;&lt;br /&gt;
    float z;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Point ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
struct Point {&lt;br /&gt;
    float x;&lt;br /&gt;
    float y;&lt;br /&gt;
    float z;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Mat4 ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
struct Mat4 {&lt;br /&gt;
    float m[4][4];&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Axis-Aligned Bounding Box ====&lt;br /&gt;
Used for collosion detection.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
struct AABB {&lt;br /&gt;
    Point endpoint1;&lt;br /&gt;
    Point endpoint2;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Mesh File Formats ===&lt;br /&gt;
A mesh describes how an object in the world needs to be rendered, all mesh file formats use little endian byte order.&lt;br /&gt;
&lt;br /&gt;
==== Common Mesh Data Types ====&lt;br /&gt;
===== Header =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
struct Header {&lt;br /&gt;
    uint u1;&lt;br /&gt;
    uint version;&lt;br /&gt;
    uint u2; // not used&lt;br /&gt;
    uint u3; // not used&lt;br /&gt;
    uint u5; // not used&lt;br /&gt;
    char u6; // not used&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== VertexElement =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
struct VertexElement {&lt;br /&gt;
    ushort flag;&lt;br /&gt;
    ushort offset;&lt;br /&gt;
    ushort varType;&lt;br /&gt;
    ushort usage;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== Geometry =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
struct Geometry {&lt;br /&gt;
    uint numGeom; // number of geometric objects in this file&lt;br /&gt;
    uint numLods[numGeom];&lt;br /&gt;
    uint numVertexElements;&lt;br /&gt;
    VertexElement vertexElements[numVertexElements]; // based on D3DXVERTEXELEMENT9&lt;br /&gt;
    uint vertexFormat;&lt;br /&gt;
    uint vertexStride;&lt;br /&gt;
    uint numVertices;&lt;br /&gt;
    float vertices[numVertices * (vertexStride / vertexFormat);&lt;br /&gt;
    uint numIndices;&lt;br /&gt;
    ushort indices[numIndices];&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== .staticmesh File Format ====&lt;br /&gt;
The .staticmesh format is used for meshes without animations, below is a description of the file layout in a C like syntax.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
struct StaticMesh {&lt;br /&gt;
    Header header;&lt;br /&gt;
    Geometry geometry;&lt;br /&gt;
    uint u6;&lt;br /&gt;
    struct Lod {&lt;br /&gt;
        Vec3 u1;&lt;br /&gt;
        Vec3 u2;&lt;br /&gt;
        uint numNodes;&lt;br /&gt;
        Mat4 nodes[numNodes]; // nodes are the respective origins of the objects?&lt;br /&gt;
    } lods[sum(geometry.numLods, geometry.numGeom)]; // each geometric object can have multiple lods&lt;br /&gt;
    struct {&lt;br /&gt;
        uint numMaterials;&lt;br /&gt;
        struct Material {&lt;br /&gt;
            uint alphaMode; // opaque = 0, blend = 1, alphatest = 2&lt;br /&gt;
            String shaderFile;&lt;br /&gt;
            String technique;&lt;br /&gt;
            uint numTextureMaps;&lt;br /&gt;
            String textureMapFiles[numTextureMaps];&lt;br /&gt;
            uint verticesStartIndex;&lt;br /&gt;
            uint indicesStartIndex;&lt;br /&gt;
            uint numIndices;&lt;br /&gt;
            uint numVertices;&lt;br /&gt;
            uint u1;&lt;br /&gt;
            ushort u2;&lt;br /&gt;
            ushort u3;&lt;br /&gt;
            Vec3 u4;&lt;br /&gt;
            Vec3 u5;&lt;br /&gt;
        } materials[numMaterials];&lt;br /&gt;
    } geomMaterials[sum(geometry.numLods, geometry.numGeom)];&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== .bundledmesh File Format ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
struct BundledMesh {&lt;br /&gt;
    Header header;&lt;br /&gt;
    Geometry geometry;&lt;br /&gt;
    uint u6;&lt;br /&gt;
    struct Lod {&lt;br /&gt;
        Vec3 u1;&lt;br /&gt;
        Vec3 u2;&lt;br /&gt;
        uint numNodes; // not used?&lt;br /&gt;
    } lods[sum(geometry.numLods, geometry.numGeom)]; // each geometric object can have multiple lods&lt;br /&gt;
    struct {&lt;br /&gt;
        uint numMaterials;&lt;br /&gt;
        struct Material {&lt;br /&gt;
            uint alphaMode; // opaque = 0, blend = 1, alphatest = 2&lt;br /&gt;
            String shaderFile;&lt;br /&gt;
            String technique;&lt;br /&gt;
            uint numTextureMaps;&lt;br /&gt;
            String textureMapFiles[numTextureMaps];&lt;br /&gt;
            uint verticesStartIndex;&lt;br /&gt;
            uint indicesStartIndex;&lt;br /&gt;
            uint numIndices;&lt;br /&gt;
            uint numVertices;&lt;br /&gt;
            uint u1;&lt;br /&gt;
            ushort u2;&lt;br /&gt;
            ushort u3;&lt;br /&gt;
        } materials[numMaterials];&lt;br /&gt;
    } geomMaterials[sum(geometry.numLods, geometry.numGeom)];&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== .skinnedmesh File Format ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
struct SkinnedMesh {&lt;br /&gt;
    Header header;&lt;br /&gt;
    Geometry geometry;&lt;br /&gt;
    struct Lod {&lt;br /&gt;
        Vec3 u1;&lt;br /&gt;
        Vec3 u2;&lt;br /&gt;
        uint numRigs;&lt;br /&gt;
        struct Rig {&lt;br /&gt;
            uint numBones;&lt;br /&gt;
            struct Bone {&lt;br /&gt;
                uint id;&lt;br /&gt;
                Mat4 mat; // inverse bone matrix&lt;br /&gt;
            } bones[numBones];&lt;br /&gt;
        } rigs[numRigs];&lt;br /&gt;
    } lods[sum(geometry.numLods, geometry.numGeom)]; // each geometric object can have multiple lods&lt;br /&gt;
    struct {&lt;br /&gt;
        uint numMaterials;&lt;br /&gt;
        struct Material {&lt;br /&gt;
            String shaderFile;&lt;br /&gt;
            String technique;&lt;br /&gt;
            uint numTextureMaps;&lt;br /&gt;
            String textureMapFiles[numTextureMaps];&lt;br /&gt;
            uint verticesStartIndex;&lt;br /&gt;
            uint indicesStartIndex;&lt;br /&gt;
            uint numIndices;&lt;br /&gt;
            uint numVertices;&lt;br /&gt;
            uint u1;&lt;br /&gt;
            ushort u2;&lt;br /&gt;
            ushort u3;&lt;br /&gt;
        } materials[numMaterials];&lt;br /&gt;
    } geomMaterials[sum(geometry.numLods, geometry.numGeom)];&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== .mesh File Format ====&lt;br /&gt;
It seems that .mesh files are only used for road data. Note that this file has a different layout.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
struct RoadCompiled {&lt;br /&gt;
    uint version; // version number consists of major and minor version, latest is 65540, 65540 &amp;gt;&amp;gt; 16 = 1, 65540 % 65536 = 4 (v1.4)&lt;br /&gt;
    Vec3 u1;&lt;br /&gt;
    uint u2;&lt;br /&gt;
    Vec3 u3;&lt;br /&gt;
    Vec3 u4;&lt;br /&gt;
    uint u5;&lt;br /&gt;
    uint numVertices;&lt;br /&gt;
    struct {&lt;br /&gt;
        Vec3 pos;&lt;br /&gt;
        Vec2 tex0;&lt;br /&gt;
        Vec2 tex1;&lt;br /&gt;
        uint alpha;&lt;br /&gt;
    } vertices[numVertices];&lt;br /&gt;
    uint numIndices;&lt;br /&gt;
    ushort indices[numIndices];&lt;br /&gt;
    uint numUnk;&lt;br /&gt;
    struct {&lt;br /&gt;
        uint u1;&lt;br /&gt;
        uint u2;&lt;br /&gt;
        uint u3;&lt;br /&gt;
        Vec3 u4;&lt;br /&gt;
    } unk[numUnk];    &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== terraindata.raw ===&lt;br /&gt;
The terraindata.raw file describes the terrain of a level in BF2.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
struct TerrainData {&lt;br /&gt;
    uint version;&lt;br /&gt;
    Vec3 primaryWorldScale;&lt;br /&gt;
    Vec3 secondaryWorldScale;&lt;br /&gt;
    float u1;&lt;br /&gt;
    float u2;&lt;br /&gt;
    float u3;&lt;br /&gt;
    uint patchSize;&lt;br /&gt;
    bool subdividePatches;&lt;br /&gt;
    uint numPatches;&lt;br /&gt;
    uint patchColormapSize;&lt;br /&gt;
    uint lowDetailmapSize;&lt;br /&gt;
    char* colorMapbaseName; // the following strings use a newline character (&#039;\n&#039;) as terminator instead of the normal null terminated C string&lt;br /&gt;
    char* detailMapbaseName;&lt;br /&gt;
    char* lowDetailMapbaseName;&lt;br /&gt;
    char* lightmapBaseName;&lt;br /&gt;
    Vec2 farSideTiling;&lt;br /&gt;
    float farSideTilingHi;&lt;br /&gt;
    float farSideTilingLow;&lt;br /&gt;
    float farYOffset;&lt;br /&gt;
    Vec3 terrainSunColor;&lt;br /&gt;
    Vec3 terrainSkyColor;&lt;br /&gt;
    Vec3 terrainWaterColor;&lt;br /&gt;
    uint numLayers; // This is always 6 for BF2, these are the layers as found in the terrain editor&lt;br /&gt;
    struct {&lt;br /&gt;
        char* detailTexturePath;&lt;br /&gt;
        char planeMap;&lt;br /&gt;
        Vec2 sideTiling;&lt;br /&gt;
        float topTiling;&lt;br /&gt;
        float yOffset;&lt;br /&gt;
        bool envMap;&lt;br /&gt;
    } layers[numLayers];&lt;br /&gt;
    uint u6[38 * 21]; // used by TerrainCuller&lt;br /&gt;
    uint u7[6 * 64];  // used by TerrainCuller&lt;br /&gt;
    uint numLodIndices;&lt;br /&gt;
    ushort lodIndices[numLodIndices];&lt;br /&gt;
    bool vertexFormat;&lt;br /&gt;
    struct QuadPatch { // This describes a rectangular region of the main terrain&lt;br /&gt;
        int x;&lt;br /&gt;
        int y;&lt;br /&gt;
        uint u3;&lt;br /&gt;
        uint u4;&lt;br /&gt;
        Vec3 position;&lt;br /&gt;
        uint u6;&lt;br /&gt;
        struct {&lt;br /&gt;
            D3DCOLOR pos0;&lt;br /&gt;
            float pos1;&lt;br /&gt;
            Vec3 morphData;&lt;br /&gt;
            D3DCOLOR normal;&lt;br /&gt;
        } compactVertexData[(patchSize + 1) * (patchSize + 1)];&lt;br /&gt;
        struct {&lt;br /&gt;
            int magic;&lt;br /&gt;
            uint index;&lt;br /&gt;
            Vec3 zero1; // always 0/0/0, no longer in use?&lt;br /&gt;
            float zero2; // no longer in use?&lt;br /&gt;
            uint numChartIndices;&lt;br /&gt;
            uint numChartIndicesDiv3; // this is equal to numChartIndices / 3&lt;br /&gt;
            uint four; // always the value 4&lt;br /&gt;
            uint numSubIndexQuads;&lt;br /&gt;
            struct SubIndexQuad {&lt;br /&gt;
                uint u1;&lt;br /&gt;
                uint u2;&lt;br /&gt;
                uint u3;&lt;br /&gt;
                uint u4;&lt;br /&gt;
                uint u5;&lt;br /&gt;
                uint u6;&lt;br /&gt;
            } subIndexQuads[numSubIndexQuads];&lt;br /&gt;
            ushort chartIndices[numChartIndices];&lt;br /&gt;
        } detailCharts[]; // this array is terminated like a string, it ends when the magic field of the next detail chart is -1&lt;br /&gt;
        uint terminator; // this will be -1, see above comment&lt;br /&gt;
    } patches[numPatches * numPatches];&lt;br /&gt;
    // here should be the data for the surrounding terrain and maybe some other data, not yet clear.&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== External Links ===&lt;br /&gt;
[http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/DDSFileReference/ddsfileformat.asp Microsoft Developer Network DDS File Reference]&lt;br /&gt;
&lt;br /&gt;
[http://www.libpng.org/pub/png/ PNG File Information]&lt;br /&gt;
&lt;br /&gt;
[http://eliteforce2.filefront.com/file/DDS_Converter;29412 DDS File Convertor]&lt;br /&gt;
&lt;br /&gt;
[http://developer.nvidia.com/object/photoshop_dds_plugins.html Nvidia DDS Plugin for reading and writing DDS files in Adobe Photoshop]&lt;br /&gt;
&lt;br /&gt;
[http://developer.nvidia.com/object/texture_atlas_tools.html Nvidia texture atlas tools reading and creating tool]&lt;/div&gt;</summary>
		<author><name>Pireax</name></author>
	</entry>
	<entry>
		<id>https://bf2tech.uturista.pt/index.php?title=File_Formats&amp;diff=154</id>
		<title>File Formats</title>
		<link rel="alternate" type="text/html" href="https://bf2tech.uturista.pt/index.php?title=File_Formats&amp;diff=154"/>
		<updated>2018-12-22T01:38:50Z</updated>

		<summary type="html">&lt;p&gt;Pireax: /* terraindata.raw */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== Image Files ===&lt;br /&gt;
The majority of the image files within the Battlefield 2 directory structure have the &#039;&#039;&#039;PNG&#039;&#039;&#039; file extension, however most of these image files are in fact &#039;&#039;&#039;DDS&#039;&#039;&#039; files with an incorrect file extension. There are a few image files that really are PNG files (mainly within &amp;lt;tt&amp;gt;Battlefield 2\mods\bf2\Objects\&amp;lt;/tt&amp;gt;), and can be easily loaded by an image viewer/editor.&lt;br /&gt;
&lt;br /&gt;
The image files in Menu_client.zip are packed into a DDS Texture Atlas file. Basicly, an atlas file combines a lot of small images into one big image to improve reading performance. An index file with coordinates is used to locate the individual images in the Atlas.&lt;br /&gt;
The Atlas images and index files are located in Menu_client.zip/Atlas.&lt;br /&gt;
&lt;br /&gt;
=== Basic File Format Data Types ===&lt;br /&gt;
==== String ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct String {&lt;br /&gt;
    uint len;&lt;br /&gt;
    char cstr[len];&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Vec2 ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
struct Vec2 {&lt;br /&gt;
    float x;&lt;br /&gt;
    float y;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Vec3 ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
struct Vec3 {&lt;br /&gt;
    float x;&lt;br /&gt;
    float y;&lt;br /&gt;
    float z;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Point ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
struct Point {&lt;br /&gt;
    float x;&lt;br /&gt;
    float y;&lt;br /&gt;
    float z;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Mat4 ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
struct Mat4 {&lt;br /&gt;
    float m[4][4];&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Axis-Aligned Bounding Box ====&lt;br /&gt;
Used for collosion detection.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
struct AABB {&lt;br /&gt;
    Point endpoint1;&lt;br /&gt;
    Point endpoint2;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Mesh File Formats ===&lt;br /&gt;
A mesh describes how an object in the world needs to be rendered, all mesh file formats use little endian byte order.&lt;br /&gt;
&lt;br /&gt;
==== Common Mesh Data Types ====&lt;br /&gt;
===== Header =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
struct Header {&lt;br /&gt;
    uint u1;&lt;br /&gt;
    uint version;&lt;br /&gt;
    uint u2; // not used&lt;br /&gt;
    uint u3; // not used&lt;br /&gt;
    uint u5; // not used&lt;br /&gt;
    char u6; // not used&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== VertexElement =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
struct VertexElement {&lt;br /&gt;
    ushort flag;&lt;br /&gt;
    ushort offset;&lt;br /&gt;
    ushort varType;&lt;br /&gt;
    ushort usage;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== Geometry =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
struct Geometry {&lt;br /&gt;
    uint numGeom; // number of geometric objects in this file&lt;br /&gt;
    uint numLods[numGeom];&lt;br /&gt;
    uint numVertexElements;&lt;br /&gt;
    VertexElement vertexElements[numVertexElements]; // based on D3DXVERTEXELEMENT9&lt;br /&gt;
    uint vertexFormat;&lt;br /&gt;
    uint vertexStride;&lt;br /&gt;
    uint numVertices;&lt;br /&gt;
    float vertices[numVertices * (vertexStride / vertexFormat);&lt;br /&gt;
    uint numIndices;&lt;br /&gt;
    ushort indices[numIndices];&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== .staticmesh File Format ====&lt;br /&gt;
The .staticmesh format is used for meshes without animations, below is a description of the file layout in a C like syntax.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
struct StaticMesh {&lt;br /&gt;
    Header header;&lt;br /&gt;
    Geometry geometry;&lt;br /&gt;
    uint u6;&lt;br /&gt;
    struct Lod {&lt;br /&gt;
        Vec3 u1;&lt;br /&gt;
        Vec3 u2;&lt;br /&gt;
        uint numNodes;&lt;br /&gt;
        Mat4 nodes[numNodes]; // nodes are the respective origins of the objects?&lt;br /&gt;
    } lods[sum(geometry.numLods, geometry.numGeom)]; // each geometric object can have multiple lods&lt;br /&gt;
    struct {&lt;br /&gt;
        uint numMaterials;&lt;br /&gt;
        struct Material {&lt;br /&gt;
            uint alphaMode; // opaque = 0, blend = 1, alphatest = 2&lt;br /&gt;
            String shaderFile;&lt;br /&gt;
            String technique;&lt;br /&gt;
            uint numTextureMaps;&lt;br /&gt;
            String textureMapFiles[numTextureMaps];&lt;br /&gt;
            uint verticesStartIndex;&lt;br /&gt;
            uint indicesStartIndex;&lt;br /&gt;
            uint numIndices;&lt;br /&gt;
            uint numVertices;&lt;br /&gt;
            uint u1;&lt;br /&gt;
            ushort u2;&lt;br /&gt;
            ushort u3;&lt;br /&gt;
            Vec3 u4;&lt;br /&gt;
            Vec3 u5;&lt;br /&gt;
        } materials[numMaterials];&lt;br /&gt;
    } geomMaterials[sum(geometry.numLods, geometry.numGeom)];&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== .bundledmesh File Format ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
struct BundledMesh {&lt;br /&gt;
    Header header;&lt;br /&gt;
    Geometry geometry;&lt;br /&gt;
    uint u6;&lt;br /&gt;
    struct Lod {&lt;br /&gt;
        Vec3 u1;&lt;br /&gt;
        Vec3 u2;&lt;br /&gt;
        uint numNodes; // not used?&lt;br /&gt;
    } lods[sum(geometry.numLods, geometry.numGeom)]; // each geometric object can have multiple lods&lt;br /&gt;
    struct {&lt;br /&gt;
        uint numMaterials;&lt;br /&gt;
        struct Material {&lt;br /&gt;
            uint alphaMode; // opaque = 0, blend = 1, alphatest = 2&lt;br /&gt;
            String shaderFile;&lt;br /&gt;
            String technique;&lt;br /&gt;
            uint numTextureMaps;&lt;br /&gt;
            String textureMapFiles[numTextureMaps];&lt;br /&gt;
            uint verticesStartIndex;&lt;br /&gt;
            uint indicesStartIndex;&lt;br /&gt;
            uint numIndices;&lt;br /&gt;
            uint numVertices;&lt;br /&gt;
            uint u1;&lt;br /&gt;
            ushort u2;&lt;br /&gt;
            ushort u3;&lt;br /&gt;
        } materials[numMaterials];&lt;br /&gt;
    } geomMaterials[sum(geometry.numLods, geometry.numGeom)];&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== .skinnedmesh File Format ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
struct SkinnedMesh {&lt;br /&gt;
    Header header;&lt;br /&gt;
    Geometry geometry;&lt;br /&gt;
    struct Lod {&lt;br /&gt;
        Vec3 u1;&lt;br /&gt;
        Vec3 u2;&lt;br /&gt;
        uint numRigs;&lt;br /&gt;
        struct Rig {&lt;br /&gt;
            uint numBones;&lt;br /&gt;
            struct Bone {&lt;br /&gt;
                uint id;&lt;br /&gt;
                Mat4 mat; // inverse bone matrix&lt;br /&gt;
            } bones[numBones];&lt;br /&gt;
        } rigs[numRigs];&lt;br /&gt;
    } lods[sum(geometry.numLods, geometry.numGeom)]; // each geometric object can have multiple lods&lt;br /&gt;
    struct {&lt;br /&gt;
        uint numMaterials;&lt;br /&gt;
        struct Material {&lt;br /&gt;
            String shaderFile;&lt;br /&gt;
            String technique;&lt;br /&gt;
            uint numTextureMaps;&lt;br /&gt;
            String textureMapFiles[numTextureMaps];&lt;br /&gt;
            uint verticesStartIndex;&lt;br /&gt;
            uint indicesStartIndex;&lt;br /&gt;
            uint numIndices;&lt;br /&gt;
            uint numVertices;&lt;br /&gt;
            uint u1;&lt;br /&gt;
            ushort u2;&lt;br /&gt;
            ushort u3;&lt;br /&gt;
        } materials[numMaterials];&lt;br /&gt;
    } geomMaterials[sum(geometry.numLods, geometry.numGeom)];&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== .mesh File Format ====&lt;br /&gt;
It seems that .mesh files are only used for road data. Note that this file has a different layout.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
struct RoadCompiled {&lt;br /&gt;
    uint version; // version number consists of major and minor version, latest is 65540, 65540 &amp;gt;&amp;gt; 16 = 1, 65540 % 65536 = 4 (v1.4)&lt;br /&gt;
    Vec3 u1;&lt;br /&gt;
    uint u2;&lt;br /&gt;
    Vec3 u3;&lt;br /&gt;
    Vec3 u4;&lt;br /&gt;
    uint u5;&lt;br /&gt;
    uint numVertices;&lt;br /&gt;
    struct {&lt;br /&gt;
        Vec3 pos;&lt;br /&gt;
        Vec2 tex0;&lt;br /&gt;
        Vec2 tex1;&lt;br /&gt;
        uint alpha;&lt;br /&gt;
    } vertices[numVertices];&lt;br /&gt;
    uint numIndices;&lt;br /&gt;
    ushort indices[numIndices];&lt;br /&gt;
    uint numUnk;&lt;br /&gt;
    struct {&lt;br /&gt;
        uint u1;&lt;br /&gt;
        uint u2;&lt;br /&gt;
        uint u3;&lt;br /&gt;
        Vec3 u4;&lt;br /&gt;
    } unk[numUnk];    &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== terraindata.raw ===&lt;br /&gt;
The terraindata.raw file describes the terrain of a level in BF2.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
struct TerrainData {&lt;br /&gt;
    uint version;&lt;br /&gt;
    Vec3 primaryWorldScale;&lt;br /&gt;
    Vec3 secondaryWorldScale;&lt;br /&gt;
    float u1;&lt;br /&gt;
    float u2;&lt;br /&gt;
    float u3;&lt;br /&gt;
    uint patchSize;&lt;br /&gt;
    bool subdividePatches;&lt;br /&gt;
    uint numPatches;&lt;br /&gt;
    uint patchColormapSize;&lt;br /&gt;
    uint lowDetailmapSize;&lt;br /&gt;
    char* colorMapbaseName; // the following strings use a newline character (&#039;\n&#039;) as terminator instead of the normal null terminated C string&lt;br /&gt;
    char* detailMapbaseName;&lt;br /&gt;
    char* lowDetailMapbaseName;&lt;br /&gt;
    char* lightmapBaseName;&lt;br /&gt;
    Vec2 farSideTiling;&lt;br /&gt;
    float farSideTilingHi;&lt;br /&gt;
    float farSideTilingLow;&lt;br /&gt;
    float farYOffset;&lt;br /&gt;
    Vec3 terrainSunColor;&lt;br /&gt;
    Vec3 terrainSkyColor;&lt;br /&gt;
    Vec3 terrainWaterColor;&lt;br /&gt;
    uint numLayers; // This is always 6 for BF2, these are the layers as found in the terrain editor&lt;br /&gt;
    struct {&lt;br /&gt;
        char* detailTexturePath;&lt;br /&gt;
        char planeMap;&lt;br /&gt;
        Vec2 sideTiling;&lt;br /&gt;
        float topTiling;&lt;br /&gt;
        float yOffset;&lt;br /&gt;
        bool envMap;&lt;br /&gt;
    } layers[numLayers];&lt;br /&gt;
    uint u6[38 * 21]; // used by TerrainCuller&lt;br /&gt;
    uint u7[6 * 64];  // used by TerrainCuller&lt;br /&gt;
    uint numIndices;&lt;br /&gt;
    ushort indices[numIndices];&lt;br /&gt;
    bool vertexFormat;&lt;br /&gt;
    struct QuadPatch { // This describes a rectangular region of the main terrain&lt;br /&gt;
        uint u1;&lt;br /&gt;
        uint u2;&lt;br /&gt;
        uint u3;&lt;br /&gt;
        uint u4;&lt;br /&gt;
        Vec3 u5;&lt;br /&gt;
        uint u6;&lt;br /&gt;
        struct {&lt;br /&gt;
            float u1;&lt;br /&gt;
            float u2;&lt;br /&gt;
            float u3;&lt;br /&gt;
            float u4;&lt;br /&gt;
            uint u5;&lt;br /&gt;
            uint u6;&lt;br /&gt;
        } compactVertexData[(patchSize + 1) * (patchSize + 1)];&lt;br /&gt;
        struct {&lt;br /&gt;
            int magic;&lt;br /&gt;
            uint i;&lt;br /&gt;
            Vec3 zero1; // always 0/0/0, no longer in use?&lt;br /&gt;
            float zero2; // no longer in use?&lt;br /&gt;
            uint numChartIndices;&lt;br /&gt;
            uint numChartIndicesDiv3; // this is equal to numChartIndices / 3&lt;br /&gt;
            uint four; // always the value 4&lt;br /&gt;
            uint numSubIndexQuads;&lt;br /&gt;
            struct SubIndexQuad {&lt;br /&gt;
                uint u1;&lt;br /&gt;
                uint u2;&lt;br /&gt;
                uint u3;&lt;br /&gt;
                uint u4;&lt;br /&gt;
                uint u5;&lt;br /&gt;
                uint u6;&lt;br /&gt;
            } subIndexQuads[numSubIndexQuads];&lt;br /&gt;
            ushort chartIndices[numChartIndices];&lt;br /&gt;
        } detailCharts[]; // this array is terminated like a string, it ends when the magic field of the next detail chart is -1&lt;br /&gt;
        uint terminator; // this will be -1, see above comment&lt;br /&gt;
    } patches[numPatches * numPatches];&lt;br /&gt;
    // here should be the data for the surrounding terrain and maybe some other data, not yet clear.&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== External Links ===&lt;br /&gt;
[http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/DDSFileReference/ddsfileformat.asp Microsoft Developer Network DDS File Reference]&lt;br /&gt;
&lt;br /&gt;
[http://www.libpng.org/pub/png/ PNG File Information]&lt;br /&gt;
&lt;br /&gt;
[http://eliteforce2.filefront.com/file/DDS_Converter;29412 DDS File Convertor]&lt;br /&gt;
&lt;br /&gt;
[http://developer.nvidia.com/object/photoshop_dds_plugins.html Nvidia DDS Plugin for reading and writing DDS files in Adobe Photoshop]&lt;br /&gt;
&lt;br /&gt;
[http://developer.nvidia.com/object/texture_atlas_tools.html Nvidia texture atlas tools reading and creating tool]&lt;/div&gt;</summary>
		<author><name>Pireax</name></author>
	</entry>
	<entry>
		<id>https://bf2tech.uturista.pt/index.php?title=Scripts:ReservedSlots&amp;diff=153</id>
		<title>Scripts:ReservedSlots</title>
		<link rel="alternate" type="text/html" href="https://bf2tech.uturista.pt/index.php?title=Scripts:ReservedSlots&amp;diff=153"/>
		<updated>2018-07-02T19:28:39Z</updated>

		<summary type="html">&lt;p&gt;Pireax: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;A small script to make sure there will always be a few reserved slots for certain players. If a non approved nick logs on and the server has reached its limit, that player will be kicked immediately.&lt;br /&gt;
&lt;br /&gt;
This script should be run as the autobalance.py and tk_punish.py scripts in the standard_admin folder, which means change the __init__.py file to include this script.&lt;br /&gt;
&lt;br /&gt;
The script is very simple, but works well. Later I might add useful bits, like not having to modify the script to approve players or change the player threshold. Also I might change the player threshold to be more dynamic, not counting approved players in the total.&lt;br /&gt;
&lt;br /&gt;
In its current form below, the nicks PLAYER1, PLAYER2 and PLAYER3 will be the only people allowed on the server once 24 players are already present.&lt;br /&gt;
&amp;lt;syntaxhighlight code=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
  # Reserved slots system for Battlefield 2&lt;br /&gt;
  # Martin Ostergaard &amp;lt;monstergod@gmail.com&amp;gt; - 2005&lt;br /&gt;
 &lt;br /&gt;
  import bf2&lt;br /&gt;
  import host&lt;br /&gt;
  from bf2 import g_debug&lt;br /&gt;
 &lt;br /&gt;
  APPROVED_PLAYERS = [&#039;PLAYER1&#039;, &#039;PLAYER2&#039;, &#039;PLAYER3&#039;]&lt;br /&gt;
  MAX_PLAYERS = 24&lt;br /&gt;
 &lt;br /&gt;
  def init():&lt;br /&gt;
     host.registerHandler(&#039;PlayerConnect&#039;, resPlayerConnect, 1)&lt;br /&gt;
     host.registerHandler(&#039;PlayerDeath&#039;, resPlayerDeath, 1)#Added by Milton&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
  def resPlayerConnect(p):&lt;br /&gt;
     ONLINEPLAYERS = len(bf2.playerManager.getPlayers())&lt;br /&gt;
    &lt;br /&gt;
     if ONLINEPLAYERS &amp;gt; MAX_PLAYERS:&lt;br /&gt;
        if APPROVED_PLAYERS.count(p.getName()) &amp;lt; 1:&lt;br /&gt;
           host.rcon_invoke(&#039;admin.kickPlayer &#039; + str(p.index))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Added by Milton&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
  def resPlayerDeath(p, vehicle):&lt;br /&gt;
      ONLINEPLAYERS = len(bf2.playerManager.getPlayers())&lt;br /&gt;
      name = p.getName()&lt;br /&gt;
      if ONLINEPLAYERS &amp;gt; MAX_PLAYERS:&lt;br /&gt;
          if APPROVED_PLAYERS.count(p.getName()) &amp;lt; 1:&lt;br /&gt;
              host.rcon_invoke(&#039;PB_SV_Kick &#039; + name + &#039; 0 Sorry, making room for members&#039;)&lt;br /&gt;
              return&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note from underplay: Im busy right now, but it wouldnt be a bad idea to check to see if the approved players are already in the server..if they are all present, allow players to connect.&lt;br /&gt;
&lt;br /&gt;
Note from monsterdog: Very nice idea, and I have already changed the running version of it substantially, for instance I have added the capability to change the approved list in runtime. I will edit the script on these pages to reflect that once I&#039;m sure it runs smoothly.&lt;br /&gt;
&lt;br /&gt;
Note from bS: I like the idea of this script, one suggestion though. If you just setup one slot as permanently free? ea. you have a 32 player server and make it 33 slots. A player could always connect to the 33rd slot, when this happens an unapproved player would be kicked stating that he connected to a reserved slot; an approved player however will cause the script to kick an unapproved player who is already on the server and thus opening a new reserved slot to repeat the procedure in the future.&lt;br /&gt;
&lt;br /&gt;
Note from Mugzy: How about using a punkbuster kick so the kicked person can see why they were kicked?&lt;br /&gt;
&lt;br /&gt;
Note from Milton: In reply to bS, I modified it a bit so that it does exactly that, when an approved player joins the next person to die that is not approved gets kicked, however the punkbuster kick will not work right as the person joins, unfortunately it seems punkbuster doesn&#039;t recognize them untill they get into the server&lt;br /&gt;
&lt;br /&gt;
Note from monsterdog: Also the PB kick appearantly lags the server a bit everytime someone is kicked. I am deliberately putting off playing more with this script until patch 1.03 is out, where it is reportedly possible to kick with a specific message popping up over the server browser. I have an updated version of the script, however, which will let you change the approved list while the server is still running:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Reserved slots system for Battlefield 2&lt;br /&gt;
  # Martin Ostergaard - 2005&lt;br /&gt;
 &lt;br /&gt;
  import bf2&lt;br /&gt;
  import host&lt;br /&gt;
  import sys&lt;br /&gt;
  from bf2 import g_debug&lt;br /&gt;
 &lt;br /&gt;
  CONFIG_FILE = &#039;/home/bf2user/bf2/admin/standard_admin/approved_players.cfg&#039;&lt;br /&gt;
  MAX_PLAYERS = 20&lt;br /&gt;
 &lt;br /&gt;
  def init():&lt;br /&gt;
     print &#039;initializing reserved slots script&#039;&lt;br /&gt;
     host.registerHandler(&#039;PlayerConnect&#039;, resPlayerConnect, 1)&lt;br /&gt;
     sys.stdout.flush()&lt;br /&gt;
 &lt;br /&gt;
  def resPlayerConnect(p):&lt;br /&gt;
     onlineplayers = len(bf2.playerManager.getPlayers())&lt;br /&gt;
     new_player = p.getName()&lt;br /&gt;
 &lt;br /&gt;
     print new_player + &#039; connected, checking for a free slot&#039;&lt;br /&gt;
 &lt;br /&gt;
     if onlineplayers &amp;gt; MAX_PLAYERS:&lt;br /&gt;
        print &#039;unreserved player max reached, checking if &#039; + new_player + &#039; is approved&#039;&lt;br /&gt;
 &lt;br /&gt;
        CONFIG_FD = open(CONFIG_FILE)&lt;br /&gt;
        APPROVED_PLAYERS = CONFIG_FD.read()&lt;br /&gt;
        CONFIG_FD.close()&lt;br /&gt;
 &lt;br /&gt;
        if APPROVED_PLAYERS.count(new_player) &amp;gt; 0:&lt;br /&gt;
           print new_player + &#039; approved for login&#039;&lt;br /&gt;
        else:&lt;br /&gt;
           print new_player + &#039; not approved, will be kicked&#039;&lt;br /&gt;
           host.rcon_invoke(&#039;admin.kickPlayer &#039; + str(p.index))&lt;br /&gt;
 &lt;br /&gt;
     sys.stdout.flush()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;approved_players.cfg&amp;quot; is simply a text file, with each players nick on a line by itself, like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  PLAYER_1&lt;br /&gt;
  PLAYER_2&lt;br /&gt;
  PLAYER_N&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Make sure you do not add any empty lines or extra stuff in there. I am pretty certain it will still work if you apply Milton&#039;s changes to it. Also note that it actually sends some debugging information out, if you have enabled some kind of error outputting.&lt;br /&gt;
&lt;br /&gt;
Note by monsterdog: OK the above was a bit redundant, saw the new reserved slots script posted on this site, which basically does almost everything I had planned to do, very nice, use that instead :-)&lt;/div&gt;</summary>
		<author><name>Pireax</name></author>
	</entry>
	<entry>
		<id>https://bf2tech.uturista.pt/index.php?title=Category:Maintenance&amp;diff=152</id>
		<title>Category:Maintenance</title>
		<link rel="alternate" type="text/html" href="https://bf2tech.uturista.pt/index.php?title=Category:Maintenance&amp;diff=152"/>
		<updated>2018-07-02T19:24:55Z</updated>

		<summary type="html">&lt;p&gt;Pireax: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Content related to the maintenance of the bf2tech wiki.&lt;/div&gt;</summary>
		<author><name>Pireax</name></author>
	</entry>
	<entry>
		<id>https://bf2tech.uturista.pt/index.php?title=Category:Maintenance&amp;diff=151</id>
		<title>Category:Maintenance</title>
		<link rel="alternate" type="text/html" href="https://bf2tech.uturista.pt/index.php?title=Category:Maintenance&amp;diff=151"/>
		<updated>2018-07-02T19:24:33Z</updated>

		<summary type="html">&lt;p&gt;Pireax: Created page with &amp;quot;Content related to the maintenance of the bf2tech wiki. Category:BF2Tech website&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Content related to the maintenance of the bf2tech wiki.&lt;br /&gt;
[[Category:BF2Tech website]]&lt;/div&gt;</summary>
		<author><name>Pireax</name></author>
	</entry>
	<entry>
		<id>https://bf2tech.uturista.pt/index.php?title=Category:Pages_with_syntax_highlighting_errors&amp;diff=150</id>
		<title>Category:Pages with syntax highlighting errors</title>
		<link rel="alternate" type="text/html" href="https://bf2tech.uturista.pt/index.php?title=Category:Pages_with_syntax_highlighting_errors&amp;diff=150"/>
		<updated>2018-07-02T19:20:07Z</updated>

		<summary type="html">&lt;p&gt;Pireax: Created page with &amp;quot;[https://www.mediawiki.org/wiki/Extension:SyntaxHighlight Extension:SyntaxHighlight] adds pages that have a bad &amp;lt;code&amp;gt;lang&amp;lt;/code&amp;gt; attribute in a &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt;&amp;lt;/nowiki...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[https://www.mediawiki.org/wiki/Extension:SyntaxHighlight Extension:SyntaxHighlight] adds pages that have a bad &amp;lt;code&amp;gt;lang&amp;lt;/code&amp;gt; attribute in a &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt;&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;&amp;lt;syntaxhighlight&amp;gt;&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; tag to this tracking category.&lt;br /&gt;
&lt;br /&gt;
The most common error that leads to pages being tagged with this category is a &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;&amp;lt;syntaxhighlight&amp;gt;&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;&amp;lt;source&amp;gt;&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; tag with no &amp;lt;code&amp;gt;lang&amp;lt;/code&amp;gt; attribute at all. These can typically be replaced with &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;&amp;lt;pre&amp;gt;&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;lang=&amp;quot;bash&amp;quot;&amp;lt;/code&amp;gt; can be added.&lt;br /&gt;
&lt;br /&gt;
The second most common error is the use of &amp;lt;code&amp;gt;lang=&amp;quot;sh&amp;quot;&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;lang=&amp;quot;shell&amp;quot;&amp;lt;/code&amp;gt; which are unsupported. These can typically be replaced with &amp;lt;code&amp;gt;lang=&amp;quot;bash&amp;quot;&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;lang=&amp;quot;shell-session&amp;quot;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
[[Category:Maintenance]]&lt;/div&gt;</summary>
		<author><name>Pireax</name></author>
	</entry>
	<entry>
		<id>https://bf2tech.uturista.pt/index.php?title=File_Formats&amp;diff=149</id>
		<title>File Formats</title>
		<link rel="alternate" type="text/html" href="https://bf2tech.uturista.pt/index.php?title=File_Formats&amp;diff=149"/>
		<updated>2018-07-02T19:16:44Z</updated>

		<summary type="html">&lt;p&gt;Pireax: /* String */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== Image Files ===&lt;br /&gt;
The majority of the image files within the Battlefield 2 directory structure have the &#039;&#039;&#039;PNG&#039;&#039;&#039; file extension, however most of these image files are in fact &#039;&#039;&#039;DDS&#039;&#039;&#039; files with an incorrect file extension. There are a few image files that really are PNG files (mainly within &amp;lt;tt&amp;gt;Battlefield 2\mods\bf2\Objects\&amp;lt;/tt&amp;gt;), and can be easily loaded by an image viewer/editor.&lt;br /&gt;
&lt;br /&gt;
The image files in Menu_client.zip are packed into a DDS Texture Atlas file. Basicly, an atlas file combines a lot of small images into one big image to improve reading performance. An index file with coordinates is used to locate the individual images in the Atlas.&lt;br /&gt;
The Atlas images and index files are located in Menu_client.zip/Atlas.&lt;br /&gt;
&lt;br /&gt;
=== Basic File Format Data Types ===&lt;br /&gt;
==== String ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct String {&lt;br /&gt;
    uint len;&lt;br /&gt;
    char cstr[len];&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Vec2 ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
struct Vec2 {&lt;br /&gt;
    float x;&lt;br /&gt;
    float y;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Vec3 ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
struct Vec3 {&lt;br /&gt;
    float x;&lt;br /&gt;
    float y;&lt;br /&gt;
    float z;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Point ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
struct Point {&lt;br /&gt;
    float x;&lt;br /&gt;
    float y;&lt;br /&gt;
    float z;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Mat4 ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
struct Mat4 {&lt;br /&gt;
    float m[4][4];&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Axis-Aligned Bounding Box ====&lt;br /&gt;
Used for collosion detection.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
struct AABB {&lt;br /&gt;
    Point endpoint1;&lt;br /&gt;
    Point endpoint2;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Mesh File Formats ===&lt;br /&gt;
A mesh describes how an object in the world needs to be rendered, all mesh file formats use little endian byte order.&lt;br /&gt;
&lt;br /&gt;
==== Common Mesh Data Types ====&lt;br /&gt;
===== Header =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
struct Header {&lt;br /&gt;
    uint u1;&lt;br /&gt;
    uint version;&lt;br /&gt;
    uint u2; // not used&lt;br /&gt;
    uint u3; // not used&lt;br /&gt;
    uint u5; // not used&lt;br /&gt;
    char u6; // not used&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== VertexElement =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
struct VertexElement {&lt;br /&gt;
    ushort flag;&lt;br /&gt;
    ushort offset;&lt;br /&gt;
    ushort varType;&lt;br /&gt;
    ushort usage;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== Geometry =====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
struct Geometry {&lt;br /&gt;
    uint numGeom; // number of geometric objects in this file&lt;br /&gt;
    uint numLods[numGeom];&lt;br /&gt;
    uint numVertexElements;&lt;br /&gt;
    VertexElement vertexElements[numVertexElements]; // based on D3DXVERTEXELEMENT9&lt;br /&gt;
    uint vertexFormat;&lt;br /&gt;
    uint vertexStride;&lt;br /&gt;
    uint numVertices;&lt;br /&gt;
    float vertices[numVertices * (vertexStride / vertexFormat);&lt;br /&gt;
    uint numIndices;&lt;br /&gt;
    ushort indices[numIndices];&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== .staticmesh File Format ====&lt;br /&gt;
The .staticmesh format is used for meshes without animations, below is a description of the file layout in a C like syntax.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
struct StaticMesh {&lt;br /&gt;
    Header header;&lt;br /&gt;
    Geometry geometry;&lt;br /&gt;
    uint u6;&lt;br /&gt;
    struct Lod {&lt;br /&gt;
        Vec3 u1;&lt;br /&gt;
        Vec3 u2;&lt;br /&gt;
        uint numNodes;&lt;br /&gt;
        Mat4 nodes[numNodes]; // nodes are the respective origins of the objects?&lt;br /&gt;
    } lods[sum(geometry.numLods, geometry.numGeom)]; // each geometric object can have multiple lods&lt;br /&gt;
    struct {&lt;br /&gt;
        uint numMaterials;&lt;br /&gt;
        struct Material {&lt;br /&gt;
            uint alphaMode; // opaque = 0, blend = 1, alphatest = 2&lt;br /&gt;
            String shaderFile;&lt;br /&gt;
            String technique;&lt;br /&gt;
            uint numTextureMaps;&lt;br /&gt;
            String textureMapFiles[numTextureMaps];&lt;br /&gt;
            uint verticesStartIndex;&lt;br /&gt;
            uint indicesStartIndex;&lt;br /&gt;
            uint numIndices;&lt;br /&gt;
            uint numVertices;&lt;br /&gt;
            uint u1;&lt;br /&gt;
            ushort u2;&lt;br /&gt;
            ushort u3;&lt;br /&gt;
            Vec3 u4;&lt;br /&gt;
            Vec3 u5;&lt;br /&gt;
        } materials[numMaterials];&lt;br /&gt;
    } geomMaterials[sum(geometry.numLods, geometry.numGeom)];&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== .bundledmesh File Format ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
struct BundledMesh {&lt;br /&gt;
    Header header;&lt;br /&gt;
    Geometry geometry;&lt;br /&gt;
    uint u6;&lt;br /&gt;
    struct Lod {&lt;br /&gt;
        Vec3 u1;&lt;br /&gt;
        Vec3 u2;&lt;br /&gt;
        uint numNodes; // not used?&lt;br /&gt;
    } lods[sum(geometry.numLods, geometry.numGeom)]; // each geometric object can have multiple lods&lt;br /&gt;
    struct {&lt;br /&gt;
        uint numMaterials;&lt;br /&gt;
        struct Material {&lt;br /&gt;
            uint alphaMode; // opaque = 0, blend = 1, alphatest = 2&lt;br /&gt;
            String shaderFile;&lt;br /&gt;
            String technique;&lt;br /&gt;
            uint numTextureMaps;&lt;br /&gt;
            String textureMapFiles[numTextureMaps];&lt;br /&gt;
            uint verticesStartIndex;&lt;br /&gt;
            uint indicesStartIndex;&lt;br /&gt;
            uint numIndices;&lt;br /&gt;
            uint numVertices;&lt;br /&gt;
            uint u1;&lt;br /&gt;
            ushort u2;&lt;br /&gt;
            ushort u3;&lt;br /&gt;
        } materials[numMaterials];&lt;br /&gt;
    } geomMaterials[sum(geometry.numLods, geometry.numGeom)];&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== .skinnedmesh File Format ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
struct SkinnedMesh {&lt;br /&gt;
    Header header;&lt;br /&gt;
    Geometry geometry;&lt;br /&gt;
    struct Lod {&lt;br /&gt;
        Vec3 u1;&lt;br /&gt;
        Vec3 u2;&lt;br /&gt;
        uint numRigs;&lt;br /&gt;
        struct Rig {&lt;br /&gt;
            uint numBones;&lt;br /&gt;
            struct Bone {&lt;br /&gt;
                uint id;&lt;br /&gt;
                Mat4 mat; // inverse bone matrix&lt;br /&gt;
            } bones[numBones];&lt;br /&gt;
        } rigs[numRigs];&lt;br /&gt;
    } lods[sum(geometry.numLods, geometry.numGeom)]; // each geometric object can have multiple lods&lt;br /&gt;
    struct {&lt;br /&gt;
        uint numMaterials;&lt;br /&gt;
        struct Material {&lt;br /&gt;
            String shaderFile;&lt;br /&gt;
            String technique;&lt;br /&gt;
            uint numTextureMaps;&lt;br /&gt;
            String textureMapFiles[numTextureMaps];&lt;br /&gt;
            uint verticesStartIndex;&lt;br /&gt;
            uint indicesStartIndex;&lt;br /&gt;
            uint numIndices;&lt;br /&gt;
            uint numVertices;&lt;br /&gt;
            uint u1;&lt;br /&gt;
            ushort u2;&lt;br /&gt;
            ushort u3;&lt;br /&gt;
        } materials[numMaterials];&lt;br /&gt;
    } geomMaterials[sum(geometry.numLods, geometry.numGeom)];&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== .mesh File Format ====&lt;br /&gt;
It seems that .mesh files are only used for road data. Note that this file has a different layout.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
struct RoadCompiled {&lt;br /&gt;
    uint version; // version number consists of major and minor version, latest is 65540, 65540 &amp;gt;&amp;gt; 16 = 1, 65540 % 65536 = 4 (v1.4)&lt;br /&gt;
    Vec3 u1;&lt;br /&gt;
    uint u2;&lt;br /&gt;
    Vec3 u3;&lt;br /&gt;
    Vec3 u4;&lt;br /&gt;
    uint u5;&lt;br /&gt;
    uint numVertices;&lt;br /&gt;
    struct {&lt;br /&gt;
        Vec3 pos;&lt;br /&gt;
        Vec2 tex0;&lt;br /&gt;
        Vec2 tex1;&lt;br /&gt;
        uint alpha;&lt;br /&gt;
    } vertices[numVertices];&lt;br /&gt;
    uint numIndices;&lt;br /&gt;
    ushort indices[numIndices];&lt;br /&gt;
    uint numUnk;&lt;br /&gt;
    struct {&lt;br /&gt;
        uint u1;&lt;br /&gt;
        uint u2;&lt;br /&gt;
        uint u3;&lt;br /&gt;
        Vec3 u4;&lt;br /&gt;
    } unk[numUnk];    &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== terraindata.raw ===&lt;br /&gt;
The terraindata.raw file describes the terrain of a level in BF2.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
struct TerrainData {&lt;br /&gt;
    uint version;&lt;br /&gt;
    Vec3 primaryWorldScale;&lt;br /&gt;
    Vec3 secondaryWorldScale;&lt;br /&gt;
    float u1;&lt;br /&gt;
    float u2;&lt;br /&gt;
    float u3;&lt;br /&gt;
    uint patchSize;&lt;br /&gt;
    bool subdividePatches;&lt;br /&gt;
    uint numPatches;&lt;br /&gt;
    uint patchColormapSize;&lt;br /&gt;
    uint lowDetailmapSize;&lt;br /&gt;
    char* colorMapbaseName; // the following strings use a newline character (&#039;\n&#039;) as terminator instead of the normal null terminated C string&lt;br /&gt;
    char* detailMapbaseName;&lt;br /&gt;
    char* lowDetailMapbaseName;&lt;br /&gt;
    char* lightmapBaseName;&lt;br /&gt;
    Vec2 farSideTiling;&lt;br /&gt;
    float farSideTilingHi;&lt;br /&gt;
    float farSideTilingLow;&lt;br /&gt;
    float farYOffset;&lt;br /&gt;
    Vec3 terrainSunColor;&lt;br /&gt;
    Vec3 terrainSkyColor;&lt;br /&gt;
    Vec3 terrainWaterColor;&lt;br /&gt;
    uint numLayers; // This is always 6 for BF2, these are the layers as found in the terrain editor&lt;br /&gt;
    struct {&lt;br /&gt;
        char* detailTexturePath;&lt;br /&gt;
        char planeMap;&lt;br /&gt;
        Vec2 sideTiling;&lt;br /&gt;
        float topTiling;&lt;br /&gt;
        float yOffset;&lt;br /&gt;
        bool envMap;&lt;br /&gt;
    } layers[numLayers];&lt;br /&gt;
    uint u6[32 * 21];&lt;br /&gt;
    uint u7[6 * 85];&lt;br /&gt;
    uint numIndices;&lt;br /&gt;
    ushort indices[numIndices];&lt;br /&gt;
    bool vertexFormat;&lt;br /&gt;
    struct QuadPatch { // This describes a rectangular region of the main terrain&lt;br /&gt;
        uint u1;&lt;br /&gt;
        uint u2;&lt;br /&gt;
        uint u3;&lt;br /&gt;
        uint u4;&lt;br /&gt;
        Vec3 u5;&lt;br /&gt;
        uint u6;&lt;br /&gt;
        struct {&lt;br /&gt;
            float u1;&lt;br /&gt;
            float u2;&lt;br /&gt;
            float u3;&lt;br /&gt;
            float u4;&lt;br /&gt;
            uint u5;&lt;br /&gt;
            uint u6;&lt;br /&gt;
        } compactVertexData[(patchSize + 1) * (patchSize + 1)];&lt;br /&gt;
        struct {&lt;br /&gt;
            int magic;&lt;br /&gt;
            uint i;&lt;br /&gt;
            Vec3 zero1; // always 0/0/0, no longer in use?&lt;br /&gt;
            float zero2; // no longer in use?&lt;br /&gt;
            uint numChartIndices;&lt;br /&gt;
            uint numChartIndicesDiv3; // this is equal to numChartIndices / 3&lt;br /&gt;
            uint four; // always the value 4&lt;br /&gt;
            uint numSubIndexQuads;&lt;br /&gt;
            struct SubIndexQuad {&lt;br /&gt;
                uint u1;&lt;br /&gt;
                uint u2;&lt;br /&gt;
                uint u3;&lt;br /&gt;
                uint u4;&lt;br /&gt;
                uint u5;&lt;br /&gt;
                uint u6;&lt;br /&gt;
            } subIndexQuads[numSubIndexQuads];&lt;br /&gt;
            ushort chartIndices[numChartIndices];&lt;br /&gt;
        } detailCharts[]; // this array is terminated like a string, it ends when the magic field of the next detail chart is -1&lt;br /&gt;
        uint terminator; // this will be -1, see above comment&lt;br /&gt;
    } patches[numPatches * numPatches];&lt;br /&gt;
    // here should be the data for the surrounding terrain and maybe some other data, not yet clear.&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== External Links ===&lt;br /&gt;
[http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/DDSFileReference/ddsfileformat.asp Microsoft Developer Network DDS File Reference]&lt;br /&gt;
&lt;br /&gt;
[http://www.libpng.org/pub/png/ PNG File Information]&lt;br /&gt;
&lt;br /&gt;
[http://eliteforce2.filefront.com/file/DDS_Converter;29412 DDS File Convertor]&lt;br /&gt;
&lt;br /&gt;
[http://developer.nvidia.com/object/photoshop_dds_plugins.html Nvidia DDS Plugin for reading and writing DDS files in Adobe Photoshop]&lt;br /&gt;
&lt;br /&gt;
[http://developer.nvidia.com/object/texture_atlas_tools.html Nvidia texture atlas tools reading and creating tool]&lt;/div&gt;</summary>
		<author><name>Pireax</name></author>
	</entry>
	<entry>
		<id>https://bf2tech.uturista.pt/index.php?title=BF2_Internals&amp;diff=139</id>
		<title>BF2 Internals</title>
		<link rel="alternate" type="text/html" href="https://bf2tech.uturista.pt/index.php?title=BF2_Internals&amp;diff=139"/>
		<updated>2018-06-25T13:40:13Z</updated>

		<summary type="html">&lt;p&gt;Pireax: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The BF2 engine has been written in C++ and also make heavy use of STL. &lt;br /&gt;
&lt;br /&gt;
{{tip}} All virtual functions on this page are in the order they are defined in the vtable unless otherwise specified.&lt;br /&gt;
&lt;br /&gt;
== Reference Counting ==&lt;br /&gt;
A lot of the internal components of the game use intrusive reference counting through inheritance.&lt;br /&gt;
The base class would look something like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class RefCounted {&lt;br /&gt;
public:&lt;br /&gt;
    RefCounted() : m_refCount(1) {}&lt;br /&gt;
&lt;br /&gt;
    virtual int addRef() {&lt;br /&gt;
        return ++m_refCount;&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    virtual int getRefCount() const {&lt;br /&gt;
        return m_refCount;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Unsure if there actually is a base implementation of this method,&lt;br /&gt;
    // this sometimes points to a unique function in the vtable but follows this pattern.&lt;br /&gt;
    virtual int release() {&lt;br /&gt;
        if (--m_refCount == 0) {&lt;br /&gt;
            delete (RefCounted*)this;&lt;br /&gt;
        }&lt;br /&gt;
        return m_refCount;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Position of the destructor in the vtable may change.&lt;br /&gt;
    virtual ~RefCounted() {}&lt;br /&gt;
private:&lt;br /&gt;
    int m_refCount;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Do note that this class is not thread-safe, as in the actual implementation.&lt;br /&gt;
&lt;br /&gt;
== ClassManager ==&lt;br /&gt;
The program contains a single ClassManager instance which is used to dynamically access different subsystems within the game.&lt;br /&gt;
These subsystems are registered via a string identifier(class name), an instance pointer, the class id and another unknown integer, they can then later be accessed using the class name.&lt;br /&gt;
The following classes are registered in BF2.exe:&lt;br /&gt;
; GameServerSettings&lt;br /&gt;
; HudInformationLayer&lt;br /&gt;
; DistributedLightRenderer&lt;br /&gt;
; LocalProfileManager&lt;br /&gt;
; ProfileManager&lt;br /&gt;
; RankManager&lt;br /&gt;
; ClanManager&lt;br /&gt;
; NewsManager&lt;br /&gt;
; AutoPatch&lt;br /&gt;
; Persistence&lt;br /&gt;
; MenuTeamManager&lt;br /&gt;
; GlobalSettings&lt;br /&gt;
; VideoSettings&lt;br /&gt;
; AudioSettings&lt;br /&gt;
; ControlSettings&lt;br /&gt;
; GeneralSettings&lt;br /&gt;
; HapticSettings&lt;br /&gt;
; ServerBrowserManager&lt;br /&gt;
; SwiffHost&lt;br /&gt;
; DemoLibrary&lt;br /&gt;
; ServerLogoManager&lt;br /&gt;
; ModInfo&lt;br /&gt;
&lt;br /&gt;
The rendering module(RendDX9.dll) also registers the following classes:&lt;br /&gt;
; SwiffRenderer&lt;br /&gt;
; Terrain&lt;br /&gt;
; LightManager&lt;br /&gt;
; GeometryTemplateManager&lt;br /&gt;
; StaticMeshRenderer&lt;br /&gt;
; SkinnedMeshRenderer&lt;br /&gt;
; ParticleSystemManager&lt;br /&gt;
; HemiMapManager&lt;br /&gt;
; DecalManager&lt;br /&gt;
; DecalShadowManager&lt;br /&gt;
; RoadCompiledRenderer&lt;br /&gt;
; RoadEditableRenderer&lt;br /&gt;
; NametagManager&lt;br /&gt;
; SkyDome&lt;br /&gt;
; UndergrowthSystem&lt;br /&gt;
; LightingManager&lt;br /&gt;
; WeatherManager&lt;br /&gt;
; RainManager&lt;br /&gt;
; RenderView&lt;br /&gt;
; EnvMapManager&lt;br /&gt;
&lt;br /&gt;
== Common ==&lt;br /&gt;
=== GameEvent ===&lt;br /&gt;
The game has multiple event systems, game events are events that occur in-game and are related to gameplay.&lt;br /&gt;
The (incomplete) class below is the base class used by all events, events often have additional data.&lt;br /&gt;
A GameEvent has a maximum size of 1024 bits as defined by &amp;lt;code&amp;gt;const uint MaximumGameEventSize&amp;lt;/code&amp;gt;.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class GameEvent : public RefCounted {&lt;br /&gt;
public:&lt;br /&gt;
    GameEvent() : field_8(-1) {}&lt;br /&gt;
    &lt;br /&gt;
    // multiple virtual functions here&lt;br /&gt;
private:&lt;br /&gt;
    int field_8;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
List of Game events:&lt;br /&gt;
; ChallengeEvent&lt;br /&gt;
; ChallengeResponseEvent&lt;br /&gt;
; ConnectionTypeEvent&lt;br /&gt;
; DataBlockEvent&lt;br /&gt;
; CreatePlayerEvent&lt;br /&gt;
; CreateObjectEvent&lt;br /&gt;
; CreateKitEvent&lt;br /&gt;
; DestroyObjectEvent&lt;br /&gt;
; DestroyPlayerEvent&lt;br /&gt;
; EnterVehicleEvent&lt;br /&gt;
; ExitVehicleEvent&lt;br /&gt;
; PostRemoteEvent&lt;br /&gt;
; ChangePlayerNameEvent&lt;br /&gt;
; HandlePickupEvent&lt;br /&gt;
; HandleDropEvent&lt;br /&gt;
; StringBlockEvent&lt;br /&gt;
; JoinSquadEvent&lt;br /&gt;
; LeaveSquadEvent&lt;br /&gt;
; CommanderEvent&lt;br /&gt;
; RadioMessageEvent&lt;br /&gt;
; KilledByEvent&lt;br /&gt;
; ChangeSquadNameEvent&lt;br /&gt;
; SetPrivateSquadEvent&lt;br /&gt;
; IssueSquadOrderEvent&lt;br /&gt;
; InviteEvent&lt;br /&gt;
; RankEvent&lt;br /&gt;
; KickBanEvent&lt;br /&gt;
; SetAcceptOrderEvent&lt;br /&gt;
; SetSquadLeaderEvent&lt;br /&gt;
; SpottedEvent&lt;br /&gt;
; ArtilleryEvent&lt;br /&gt;
; StickyProjectileEvent&lt;br /&gt;
; AmbientEffectAreaEvent&lt;br /&gt;
; VoipOnOffEvent&lt;br /&gt;
; CommanderCamEvent&lt;br /&gt;
; SupplyDropEvent&lt;br /&gt;
; VoidPlayerMuteEvent&lt;br /&gt;
; VoteEvent&lt;br /&gt;
; TargetDirectionEvent&lt;br /&gt;
; BeginRoundEvent&lt;br /&gt;
; EndOfRoundEvent&lt;br /&gt;
; PythonCommandEvent&lt;br /&gt;
; RequestEvent&lt;br /&gt;
; VoipSessionEvent&lt;br /&gt;
; ToggleFreeCameraEvent&lt;br /&gt;
; MedalEvent&lt;br /&gt;
; UnlockEvent&lt;br /&gt;
; MissileInitEvent&lt;br /&gt;
; UAVEvent&lt;br /&gt;
; ContentCheckEvent&lt;br /&gt;
; DropVehicleEvent&lt;br /&gt;
; CreateSpawnGroupEvent&lt;br /&gt;
; RemoveSpawnGroupEvent&lt;br /&gt;
; UpdateTriggerEvent&lt;br /&gt;
; GrapplingHookContainerCreateEvent&lt;br /&gt;
; GrapplingHookContainerUpdateEvent&lt;br /&gt;
; GrapplingHookContainerDetachEvent&lt;br /&gt;
; GrapplingHookCreateEvent&lt;br /&gt;
; GrapplingHookUpdateEvent&lt;br /&gt;
; PlayerTearGassedEvent&lt;br /&gt;
; SetNightVisionEvent&lt;br /&gt;
; VerifyPlayerTeamEvent&lt;br /&gt;
; FixPlayerTeamEvent&lt;/div&gt;</summary>
		<author><name>Pireax</name></author>
	</entry>
	<entry>
		<id>https://bf2tech.uturista.pt/index.php?title=Template:Tip&amp;diff=138</id>
		<title>Template:Tip</title>
		<link rel="alternate" type="text/html" href="https://bf2tech.uturista.pt/index.php?title=Template:Tip&amp;diff=138"/>
		<updated>2018-06-25T13:38:09Z</updated>

		<summary type="html">&lt;p&gt;Pireax: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[File:Bulbgraph.png|18px|Note|link=]]&amp;amp;nbsp;&#039;&#039;&#039;Note:&#039;&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Pireax</name></author>
	</entry>
	<entry>
		<id>https://bf2tech.uturista.pt/index.php?title=Template:Tip&amp;diff=137</id>
		<title>Template:Tip</title>
		<link rel="alternate" type="text/html" href="https://bf2tech.uturista.pt/index.php?title=Template:Tip&amp;diff=137"/>
		<updated>2018-06-25T13:37:15Z</updated>

		<summary type="html">&lt;p&gt;Pireax: Created page with &amp;quot;&amp;lt;onlyinclude&amp;gt;     link=&amp;amp;nbsp;&amp;#039;&amp;#039;&amp;#039;Note:&amp;#039;&amp;#039;&amp;#039; &amp;lt;/onlyinclude&amp;gt;&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;onlyinclude&amp;gt;&lt;br /&gt;
    [[File:Bulbgraph.png|18px|Note|link=]]&amp;amp;nbsp;&#039;&#039;&#039;Note:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;/onlyinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>Pireax</name></author>
	</entry>
	<entry>
		<id>https://bf2tech.uturista.pt/index.php?title=File:Bulbgraph.png&amp;diff=136</id>
		<title>File:Bulbgraph.png</title>
		<link rel="alternate" type="text/html" href="https://bf2tech.uturista.pt/index.php?title=File:Bulbgraph.png&amp;diff=136"/>
		<updated>2018-06-25T13:31:34Z</updated>

		<summary type="html">&lt;p&gt;Pireax: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Pireax</name></author>
	</entry>
	<entry>
		<id>https://bf2tech.uturista.pt/index.php?title=Scripts:TK_punish_announcer&amp;diff=135</id>
		<title>Scripts:TK punish announcer</title>
		<link rel="alternate" type="text/html" href="https://bf2tech.uturista.pt/index.php?title=Scripts:TK_punish_announcer&amp;diff=135"/>
		<updated>2018-06-22T15:38:55Z</updated>

		<summary type="html">&lt;p&gt;Pireax: Created page with &amp;quot;__TOC__ = Introduction =  One of the major frustrations in BF2 is the often observed abuse of the PTK function. Since it is so easily available, many people punish others for...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
One of the major frustrations in BF2 is the often observed abuse of the PTK function. Since it is so easily available, many people punish others for TKs even when it&#039;s their own fault. At [http://www.battlefield.no/ Battlefield.no] we do not accept this behaviour, but it can be very hard for admins to take notice of people doing this. We have therefore made a modification to the tk_punish.py-script which is included with BF2.&lt;br /&gt;
&lt;br /&gt;
= Features =&lt;br /&gt;
&lt;br /&gt;
For each player a running tally of the number of forgives and punishes is kept. Whenever someone punishes a TK, a global announcement is made on the server indicating how many punishes and forgives this person has made. This makes it easy to spot people abusing the PTK-system.&lt;br /&gt;
&lt;br /&gt;
This script is a drop-in replacement for the original tk_punish.py which comes with BF2. It is based on the script from the 1.12 release (build 1.1.2554-356). No functionality of the original script has been removed, so this script should be allowed on ranked servers.&lt;br /&gt;
&lt;br /&gt;
= Getting started =&lt;br /&gt;
&lt;br /&gt;
Copy the script from below and replace your current tk_punish.py which you can find under bf2/admin/standard_admin. Remember to make a backup of the original script first!&lt;br /&gt;
&lt;br /&gt;
= The code =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
The code&lt;br /&gt;
&lt;br /&gt;
# tk punish system&lt;br /&gt;
&lt;br /&gt;
import bf2&lt;br /&gt;
import host&lt;br /&gt;
from bf2 import g_debug&lt;br /&gt;
&lt;br /&gt;
TK_PUNISH_TIME = 20&lt;br /&gt;
TK_PUNISH_COMMANDID = 100&lt;br /&gt;
TK_FORGIVE_COMMANDID = 101&lt;br /&gt;
&lt;br /&gt;
hasPendingTks = {}&lt;br /&gt;
updateTimer = None&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class TkData:&lt;br /&gt;
        def __init__(self):&lt;br /&gt;
                self.punished = 0&lt;br /&gt;
                self.pending = []&lt;br /&gt;
                self.lastTKedBy = None&lt;br /&gt;
                self.givenPunish = 0 # bf.no modification&lt;br /&gt;
                self.givenForgive = 0 # bf.no modification&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def init():&lt;br /&gt;
        if g_debug: print &amp;quot;initializing tk-punish script&amp;quot;&lt;br /&gt;
&lt;br /&gt;
        host.registerHandler(&#039;PlayerConnect&#039;, onPlayerConnect, 1)&lt;br /&gt;
        host.registerHandler(&#039;PlayerKilled&#039;, onPlayerKilled)&lt;br /&gt;
        host.registerHandler(&#039;ClientCommand&#039;, onClientCommand)&lt;br /&gt;
&lt;br /&gt;
        # Connect already connected players if reinitializing&lt;br /&gt;
        for p in bf2.playerManager.getPlayers():&lt;br /&gt;
                onPlayerConnect(p)&lt;br /&gt;
       &lt;br /&gt;
        checkEnable()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def checkEnable():&lt;br /&gt;
        global updateTimer&lt;br /&gt;
       &lt;br /&gt;
        if not bf2.serverSettings.getTKPunishEnabled():&lt;br /&gt;
                if updateTimer:&lt;br /&gt;
                        updateTimer.destroy()&lt;br /&gt;
                        updateTimer = None&lt;br /&gt;
                return False&lt;br /&gt;
        else:&lt;br /&gt;
                if not updateTimer:&lt;br /&gt;
                        #if g_debug: print &amp;quot;Started timer&amp;quot;&lt;br /&gt;
                        updateTimer = bf2.Timer(onUpdate, 10, 1)&lt;br /&gt;
                        updateTimer.setRecurring(10)&lt;br /&gt;
                       &lt;br /&gt;
                return True&lt;br /&gt;
       &lt;br /&gt;
&lt;br /&gt;
def onUpdate(data):&lt;br /&gt;
        if not checkEnable(): return&lt;br /&gt;
        global hasPendingTks&lt;br /&gt;
&lt;br /&gt;
        #if len(hasPendingTks) &amp;gt; 0:&lt;br /&gt;
        #       if g_debug: print &amp;quot;update: Has pending tks!&amp;quot;&lt;br /&gt;
        #else:&lt;br /&gt;
        #       if g_debug: print &amp;quot;update:No pending tks.&amp;quot;&lt;br /&gt;
               &lt;br /&gt;
&lt;br /&gt;
        currentTime = host.timer_getWallTime()&lt;br /&gt;
&lt;br /&gt;
        newPending = {}&lt;br /&gt;
        for attacker in hasPendingTks.iterkeys():&lt;br /&gt;
                newList = []&lt;br /&gt;
                #if g_debug: print &amp;quot;attacker pending list:&amp;quot;, len(attacker.tkData.pending)&lt;br /&gt;
                for tk in attacker.tkData.pending:&lt;br /&gt;
                        tkDate = tk[0]&lt;br /&gt;
                        tkVictim = tk[1]&lt;br /&gt;
                        #if g_debug: print &amp;quot;check %d %s&amp;quot; % (tkDate, tkVictim.getName())&lt;br /&gt;
&lt;br /&gt;
                        # if there is a pending TK with time expired&lt;br /&gt;
                        if tkDate + TK_PUNISH_TIME &amp;lt; currentTime:&lt;br /&gt;
                                if bf2.serverSettings.getTKPunishByDefault():&lt;br /&gt;
                                        attacker.tkData.punished += 1&lt;br /&gt;
                                        checkPunishLimit(attacker)&lt;br /&gt;
                                        # bf.no addons:&lt;br /&gt;
                                        tkVictim.tkData.givenPunish += 1&lt;br /&gt;
                                        result = host.rcon_invoke(&#039;game.sayAll &amp;quot;TKPUNISH: %s punishes %s for teamkill (%s has %d punishes and %d forgives)&amp;quot;&#039; % (tkVictim.getName(), attacker.getName(), tkVictim.getName(), tkVictim.tkData.givenPunish, tkVictim.tkData.givenForgive))&lt;br /&gt;
                                        # *************&lt;br /&gt;
                                #       if g_debug: print &amp;quot;Default punished &amp;quot;, attacker.getName()&lt;br /&gt;
                                else:&lt;br /&gt;
                                        # bf.no addons:&lt;br /&gt;
                                        tkVictim.tkData.givenForgive += 1&lt;br /&gt;
                                #       if g_debug: print &amp;quot;Timeouted pending tk for &amp;quot;, attacker.getName()&lt;br /&gt;
                                        # pass&lt;br /&gt;
&lt;br /&gt;
                                # remove player from global list, if it was the last tk&lt;br /&gt;
                                if len(attacker.tkData.pending) == 1:&lt;br /&gt;
                                        pass&lt;br /&gt;
                                else:&lt;br /&gt;
                                        newPending[attacker] = 1&lt;br /&gt;
                       &lt;br /&gt;
                        else:&lt;br /&gt;
                                newList += [tk]&lt;br /&gt;
                                newPending[attacker] = 1&lt;br /&gt;
               &lt;br /&gt;
                attacker.tkData.pending = newList&lt;br /&gt;
&lt;br /&gt;
        hasPendingTks = newPending&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def checkPunishLimit(player):&lt;br /&gt;
        #if g_debug: print &amp;quot;player %s has %d punishes&amp;quot; % (player.getName(), player.tkData.punished)&lt;br /&gt;
&lt;br /&gt;
        if player.tkData.punished &amp;gt;= bf2.serverSettings.getTKNumPunishToKick():&lt;br /&gt;
                if g_debug: print &amp;quot;%s reached punish limit&amp;quot; % player.getName()&lt;br /&gt;
                if g_debug: print &amp;quot;Banning player!&amp;quot;&lt;br /&gt;
                result = host.rcon_invoke(&amp;quot;admin.banPlayerKey &amp;quot; + str(player.index) + &amp;quot; Round&amp;quot;)&lt;br /&gt;
               &lt;br /&gt;
       &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# event actions&lt;br /&gt;
&lt;br /&gt;
def onPlayerConnect(player):&lt;br /&gt;
        player.tkData = TkData()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def onClientCommand(command, issuer, args):&lt;br /&gt;
        if not checkEnable(): return&lt;br /&gt;
       &lt;br /&gt;
        #if g_debug: print &amp;quot;received client command&amp;quot;&lt;br /&gt;
        if command == TK_PUNISH_COMMANDID:&lt;br /&gt;
                executePunishAction(issuer, True)&lt;br /&gt;
        elif command == TK_FORGIVE_COMMANDID:&lt;br /&gt;
                executePunishAction(issuer, False)&lt;br /&gt;
&lt;br /&gt;
               &lt;br /&gt;
&lt;br /&gt;
def onPlayerKilled(victim, attacker, weapon, assists, object):&lt;br /&gt;
&lt;br /&gt;
        if not checkEnable(): return&lt;br /&gt;
&lt;br /&gt;
        if not victim or not attacker or victim == attacker or victim.getTeam() != attacker.getTeam(): return&lt;br /&gt;
       &lt;br /&gt;
        # verify that TK was really given&lt;br /&gt;
&lt;br /&gt;
        # no teamkills from wrecks&lt;br /&gt;
        if object != None and object.getIsWreck():&lt;br /&gt;
                return&lt;br /&gt;
               &lt;br /&gt;
        # no teamkills from artillery&lt;br /&gt;
        if weapon:&lt;br /&gt;
                attackerVehicle = bf2.objectManager.getRootParent(weapon)&lt;br /&gt;
                if attackerVehicle.isPlayerControlObject and attackerVehicle.getIsRemoteControlled():&lt;br /&gt;
                        return&lt;br /&gt;
               &lt;br /&gt;
        # ok, we have a teamkill&lt;br /&gt;
        currentTime = host.timer_getWallTime()&lt;br /&gt;
        attacker.tkData.pending += [(currentTime, victim)]&lt;br /&gt;
        hasPendingTks[attacker] = 1&lt;br /&gt;
               &lt;br /&gt;
        victim.tkData.lastTKedBy = attacker # can only punish / forgive the last TK&#039;er&lt;br /&gt;
       &lt;br /&gt;
        bf2.gameLogic.sendClientCommand(victim.index, 100, (2, victim.index, attacker.index, TK_PUNISH_TIME))&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def executePunishAction(victim, punish):&lt;br /&gt;
        if not checkEnable() or not victim or not victim.isValid(): return&lt;br /&gt;
        attacker = victim.tkData.lastTKedBy&lt;br /&gt;
        if attacker == None or not attacker.isValid(): return&lt;br /&gt;
&lt;br /&gt;
        global hasPendingTks&lt;br /&gt;
&lt;br /&gt;
        if punish:&lt;br /&gt;
                if g_debug: print &amp;quot;%s tkPunished %s&amp;quot; % (victim.getName(), attacker.getName())&lt;br /&gt;
        else:&lt;br /&gt;
                if g_debug: print &amp;quot;%s tkForgive %s&amp;quot; % (victim.getName(), attacker.getName())&lt;br /&gt;
&lt;br /&gt;
        currentTime = host.timer_getWallTime()&lt;br /&gt;
       &lt;br /&gt;
        newList = []&lt;br /&gt;
        for tk in attacker.tkData.pending:&lt;br /&gt;
                tkDate = tk[0]&lt;br /&gt;
                tkVictim = tk[1]&lt;br /&gt;
               &lt;br /&gt;
                # if the attacker had a pending tk, and time has not run out&lt;br /&gt;
                if tkVictim == victim and tkDate + TK_PUNISH_TIME &amp;gt; currentTime:&lt;br /&gt;
                        if punish:&lt;br /&gt;
                                attacker.tkData.punished += 1&lt;br /&gt;
                                bf2.gameLogic.sendClientCommand(-1, 100, (0, victim.index, attacker.index)) # 100 = tkpunish event, 0 = punish&lt;br /&gt;
                                if g_debug: print &amp;quot;%s punished %s, now has %d punishes&amp;quot; % (victim.getName(), attacker.getName(), attacker.tkData.punished)&lt;br /&gt;
                                # bf.no addons:&lt;br /&gt;
                                victim.tkData.givenPunish += 1&lt;br /&gt;
                                result = host.rcon_invoke(&#039;game.sayAll &amp;quot;TKPUNISH: %s punishes %s for teamkill (%s has %d punishes and %d forgives)&amp;quot;&#039; % (victim.getName(), attacker.getName(), victim.getName(), victim.tkData.givenPunish, victim.tkData.givenForgive))&lt;br /&gt;
                                # *************&lt;br /&gt;
                        else:&lt;br /&gt;
                                bf2.gameLogic.sendClientCommand(-1, 100, (1, victim.index, attacker.index)) # 100 = tkpunish event, 1 = forgive&lt;br /&gt;
                                if g_debug: print &amp;quot;%s forgave %s&amp;quot; % (victim.getName(), attacker.getName())&lt;br /&gt;
                                # bf.no addons:&lt;br /&gt;
                                victim.tkData.givenForgive += 1&lt;br /&gt;
                else:&lt;br /&gt;
                        newList += [tk]&lt;br /&gt;
                       &lt;br /&gt;
        attacker.tkData.pending = newList&lt;br /&gt;
       &lt;br /&gt;
        if len(attacker.tkData.pending) == 0:&lt;br /&gt;
                del hasPendingTks[attacker]&lt;br /&gt;
       &lt;br /&gt;
        checkPunishLimit(attacker)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Pireax</name></author>
	</entry>
	<entry>
		<id>https://bf2tech.uturista.pt/index.php?title=Scripts:ModifiedDemoRotator&amp;diff=134</id>
		<title>Scripts:ModifiedDemoRotator</title>
		<link rel="alternate" type="text/html" href="https://bf2tech.uturista.pt/index.php?title=Scripts:ModifiedDemoRotator&amp;diff=134"/>
		<updated>2018-06-22T15:38:39Z</updated>

		<summary type="html">&lt;p&gt;Pireax: Created page with &amp;quot;__TOC__ ==  What It Does  ==  * Checks to see if your demo path and demo target path are the same before moving. This is mainly only useful if you don&amp;#039;t want your demos moved,...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
==  What It Does  ==&lt;br /&gt;
&lt;br /&gt;
* Checks to see if your demo path and demo target path are the same before moving. This is mainly only useful if you don&#039;t want your demos moved, but you still want them regularly pruned. (Or if you have your demo path symlinked to your web directory.)&lt;br /&gt;
* &amp;lt;code&amp;gt;chmod&amp;lt;/code&amp;gt;s all demo files &amp;lt;code&amp;gt;0644&amp;lt;/code&amp;gt; so they can be downloaded through the web or in-game.&lt;br /&gt;
&lt;br /&gt;
==  Installation  ==&lt;br /&gt;
&lt;br /&gt;
# Browser to &amp;lt;code&amp;gt;adminutils/demo/&amp;lt;/code&amp;gt; in your bf2 server directory&lt;br /&gt;
# Backup &amp;lt;code&amp;gt;rotate_demo.py&amp;lt;/code&amp;gt;. (&amp;lt;code&amp;gt;cp rotate_demo.py rotate_demo.py.bak&amp;lt;/code&amp;gt;.)&lt;br /&gt;
# Download rotate_demo.py.patch or copy the below text into a file manually.&lt;br /&gt;
# Patch &amp;lt;code&amp;gt;rotate_demo.py&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;patch -p0 rotate_demo.py &amp;lt; rotate_demo.py.patch&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Code  ==&lt;br /&gt;
&lt;br /&gt;
===  Downloadable  ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;s&amp;gt;[http://dackz.net/misc/code/rotate_demo/rotate_demo.py.patch http://dackz.net/misc/code/rotate_demo/rotate_demo.py.patch]&amp;lt;/s&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Readable  ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
--- rotate_demo.py.orig    2005-06-26 16:02:51.000000000 -0400&lt;br /&gt;
+++ rotate_demo.py    2005-06-26 16:06:34.000000000 -0400&lt;br /&gt;
@@ -79,13 +79,14 @@&lt;br /&gt;
     ensure_exists(os.path.join(options[&#039;target_root&#039;], &#039;demos&#039;))&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
-    # try to move the fail, or fail miserably&lt;br /&gt;
-    try:&lt;br /&gt;
-        # NOTE: this requires atleast Python 2.3&lt;br /&gt;
-        print &amp;quot;moving &#039;%s&#039; to &#039;%s&#039;&amp;quot; % (path, target_demo_dir)&lt;br /&gt;
-        shutil.move(path, target_demo_dir)&lt;br /&gt;
-    except IOError:&lt;br /&gt;
-        sys.exit(1)&lt;br /&gt;
+    # don&#039;t move if path and target are the same&lt;br /&gt;
+    if os.path.abspath(os.path.dirname(path)) != os.path.abspath(target_demo_dir):&lt;br /&gt;
+        try:&lt;br /&gt;
+            # NOTE: this requires atleast Python 2.3&lt;br /&gt;
+            print &amp;quot;moving &#039;%s&#039; to &#039;%s&#039;&amp;quot; % (path, target_demo_dir)&lt;br /&gt;
+            shutil.move(path, target_demo_dir)&lt;br /&gt;
+        except IOError:&lt;br /&gt;
+            sys.exit(1)&lt;br /&gt;
 &lt;br /&gt;
     timestamped = []&lt;br /&gt;
 &lt;br /&gt;
@@ -93,6 +94,7 @@&lt;br /&gt;
     for pf in filter(lambda x: x.endswith(&#039;.bf2demo&#039;), os.listdir(target_demo_dir)):&lt;br /&gt;
         try:&lt;br /&gt;
             ppath = os.path.join(target_demo_dir, pf)&lt;br /&gt;
+            os.chmod(ppath, 0644) # make web-readable&lt;br /&gt;
             timestamped.append((os.stat(ppath).st_mtime, ppath))&lt;br /&gt;
         except IOError:&lt;br /&gt;
             pass # don&#039;t let I/O errors stop us&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Pireax</name></author>
	</entry>
	<entry>
		<id>https://bf2tech.uturista.pt/index.php?title=Scripts:ClanmemberBalance&amp;diff=133</id>
		<title>Scripts:ClanmemberBalance</title>
		<link rel="alternate" type="text/html" href="https://bf2tech.uturista.pt/index.php?title=Scripts:ClanmemberBalance&amp;diff=133"/>
		<updated>2018-06-22T15:38:25Z</updated>

		<summary type="html">&lt;p&gt;Pireax: Created page with &amp;quot;__TOC__ == Short Description  ==  &amp;#039;&amp;#039;&amp;#039;Autobalance unleashed by Nexus2k:&amp;#039;&amp;#039;&amp;#039;  This Modification prevent Clanmembers/Commanders/Squadleaders and Squad Members from Autobalance and...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
== Short Description  ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Autobalance unleashed by Nexus2k:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This Modification prevent Clanmembers/Commanders/Squadleaders and Squad Members from Autobalance and additionally switchs Clanmembers to one Team on connect&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Protect Clanmembers/Commander/Squadleader from Autobalance:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Open bf2/admin/standard_admin/autobalance.py with a texteditor Add at Line 7:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Change this to your Clantag&lt;br /&gt;
clantag=&amp;quot;Net.BS|&amp;quot; &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And add at Line 46, after:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;if not bf2.serverSettings.getAutoBalanceTeam(): return &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        # Prevent Clanmembers from Autobalancing&lt;br /&gt;
        name=p.getName()&lt;br /&gt;
        if name.find(clantag)&amp;gt;-1: return None&lt;br /&gt;
       &lt;br /&gt;
        # Squadleader/Commander prevent from Change&lt;br /&gt;
        if p.isCommander(): return None&lt;br /&gt;
        if p.isSquadLeader(): return None&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
--Nexus2k 05:46, 18 Jul 2005 (MDT)&lt;br /&gt;
&lt;br /&gt;
==  Additions  ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;For more than one Clan Tag:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Modifiy the clantag variable: from:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Change this to your Clantag&lt;br /&gt;
clantag=&amp;quot;Net.BS|&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
to&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Insert here your Clantags&lt;br /&gt;
clantags=[&amp;quot;Net.BS|&amp;quot;,&amp;quot;|CSAR|&amp;quot;]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and from:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Prevent Clanmembers from Autobalancing&lt;br /&gt;
name=p.getName()&lt;br /&gt;
if name.find(clantag)&amp;gt;-1: return None&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
to&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Prevent Clanmembers from Autobalancing&lt;br /&gt;
name=p.getName()&lt;br /&gt;
for clantag in clantags:&lt;br /&gt;
 if name.find(clantag)&amp;gt;-1: return None&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Squadmemberautobalanceprotection:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
(From ~RIP~Brian on [http://bf1942.lightcubed.com/forum/viewtopic.php?p=14370#14370 http://bf1942.lightcubed.com/forum/viewtopic.php?p=14370#14370]) add after this section :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Prevent Clanmembers from Autobalancing&lt;br /&gt;
        name=p.getName()&lt;br /&gt;
&lt;br /&gt;
        if name.find(clantag)&amp;gt;-1: return None&lt;br /&gt;
        # Squadleader/Commander prevent from Change&lt;br /&gt;
        if p.isCommander(): return None if p.isSquadLeader(): return None&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
the following code&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Prevent squad members from change&lt;br /&gt;
if p.getSquadId()&amp;gt;0: return None&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==  More Additions  ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Auto TeamSet on Connect:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Open autobalance.py add after:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if team2 &amp;gt; team1:&lt;br /&gt;
                p.setTeam(1)&lt;br /&gt;
        else:&lt;br /&gt;
                p.setTeam(2)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
this code part for only One Clan:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#change Team to 1 on Connect if Clanmember&lt;br /&gt;
name=p.getName()&lt;br /&gt;
if name.find(clantag)&amp;gt;-1: p.setTeam(1)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
or this code part for multiple Clans:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#change Team to 1 on Connect if Clanmember&lt;br /&gt;
name=p.getName()&lt;br /&gt;
for clantag in clantags:&lt;br /&gt;
 if name.find(clantag)&amp;gt;-1: p.setTeam(1)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example  ==&lt;br /&gt;
&lt;br /&gt;
The whole autobalance.py can look like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Example&lt;br /&gt;
&lt;br /&gt;
The whole autobalance.py can look like this:&lt;br /&gt;
&lt;br /&gt;
# team autobalance system&lt;br /&gt;
&lt;br /&gt;
import bf2&lt;br /&gt;
import host&lt;br /&gt;
from bf2 import g_debug&lt;br /&gt;
&lt;br /&gt;
#Insert here your Clantags&lt;br /&gt;
clantags=[&amp;quot;Net.BS|&amp;quot;,&amp;quot;|CSAR|&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
def init():&lt;br /&gt;
        if g_debug: print &#039;initializing autobalance script&#039;&lt;br /&gt;
&lt;br /&gt;
        host.registerHandler(&#039;PlayerConnect&#039;, onPlayerConnect)&lt;br /&gt;
        host.registerHandler(&#039;PlayerDeath&#039;, onPlayerDeath)&lt;br /&gt;
        host.registerHandler(&#039;PlayerChangeTeams&#039;, onPlayerChangeTeams)&lt;br /&gt;
&lt;br /&gt;
def onPlayerConnect(p):&lt;br /&gt;
&lt;br /&gt;
        # dont teamswitch alive players, or they will have the wrong teams kit&lt;br /&gt;
        if p.isAlive(): return&lt;br /&gt;
&lt;br /&gt;
        # place player on the team with least players&lt;br /&gt;
        team1 = 0&lt;br /&gt;
        team2 = 0&lt;br /&gt;
        for tp in bf2.playerManager.getPlayers():&lt;br /&gt;
                if tp != p:&lt;br /&gt;
                        if tp.getTeam() == 1: team1 += 1&lt;br /&gt;
                        else: team2 += 1&lt;br /&gt;
&lt;br /&gt;
        team2 = team2 * bf2.serverSettings.getTeamRatioPercent() / 100.0       &lt;br /&gt;
        if team2 &amp;gt; team1:&lt;br /&gt;
                p.setTeam(1)&lt;br /&gt;
        else:&lt;br /&gt;
                p.setTeam(2)&lt;br /&gt;
        #change Team to 1 on Connect if Clanmember&lt;br /&gt;
        name=p.getName()&lt;br /&gt;
        for clantag in clantags:&lt;br /&gt;
         if name.find(clantag)&amp;gt;-1: p.setTeam(1)&lt;br /&gt;
&lt;br /&gt;
def onPlayerDeath(p, vehicle):&lt;br /&gt;
&lt;br /&gt;
        if not bf2.serverSettings.getAutoBalanceTeam(): return&lt;br /&gt;
&lt;br /&gt;
        # Prevent Clanmembers from Autobalancing&lt;br /&gt;
        name=p.getName()&lt;br /&gt;
        for clantag in clantags:&lt;br /&gt;
         if name.find(clantag)&amp;gt;-1: return None&lt;br /&gt;
&lt;br /&gt;
        # Squadleader/Commander prevent from Change&lt;br /&gt;
        if p.isCommander(): return None&lt;br /&gt;
        if p.isSquadLeader(): return None&lt;br /&gt;
&lt;br /&gt;
        # Prevent squad members from change&lt;br /&gt;
        if p.getSquadId()&amp;gt;0: return None&lt;br /&gt;
&lt;br /&gt;
        # dont use autobalance when its suicide/changes team&lt;br /&gt;
        if p.getSuicide():&lt;br /&gt;
                p.setSuicide(0)&lt;br /&gt;
                return&lt;br /&gt;
&lt;br /&gt;
        aiPlayerBalance = 0&lt;br /&gt;
        team1 = 0&lt;br /&gt;
        team2 = 0&lt;br /&gt;
        for tp in bf2.playerManager.getPlayers():&lt;br /&gt;
                if tp.getTeam() == 1:&lt;br /&gt;
                        team1 += 1&lt;br /&gt;
                else:&lt;br /&gt;
                        team2 += 1&lt;br /&gt;
                if tp.isAIPlayer():&lt;br /&gt;
                        aiPlayerBalance += 1&lt;br /&gt;
                else:&lt;br /&gt;
                        aiPlayerBalance -= 1&lt;br /&gt;
&lt;br /&gt;
        if host.sgl_getIsAIGame():&lt;br /&gt;
                if not (aiPlayerBalance &amp;lt; 0):&lt;br /&gt;
                        if not p.isAIPlayer():&lt;br /&gt;
                                return&lt;br /&gt;
&lt;br /&gt;
        team2 = team2 * bf2.serverSettings.getTeamRatioPercent() / 100.0&lt;br /&gt;
&lt;br /&gt;
        if (p.getTeam() == 1):&lt;br /&gt;
                if (team2+1) &amp;lt; team1:&lt;br /&gt;
                        p.setTeam(2)&lt;br /&gt;
        elif (p.getTeam() == 2):&lt;br /&gt;
                if (team1+1) &amp;lt; team2:&lt;br /&gt;
                        p.setTeam(1)&lt;br /&gt;
&lt;br /&gt;
def onPlayerChangeTeams(p, humanHasSpawned):&lt;br /&gt;
&lt;br /&gt;
        if not bf2.serverSettings.getAutoBalanceTeam(): return&lt;br /&gt;
&lt;br /&gt;
        # dont teamswitch alive players, or they will have the wrong teams kit&lt;br /&gt;
        if p.isAlive(): return&lt;br /&gt;
&lt;br /&gt;
        if host.sgl_getIsAIGame():&lt;br /&gt;
                if humanHasSpawned: return&lt;br /&gt;
                if p.isAIPlayer(): return&lt;br /&gt;
&lt;br /&gt;
                # handling aiplayer team change autobalance when round not started&lt;br /&gt;
                team = p.getTeam()&lt;br /&gt;
                aiplayer = 0&lt;br /&gt;
&lt;br /&gt;
                for tp in bf2.playerManager.getPlayers():&lt;br /&gt;
                        if aiplayer == 0 and tp.getTeam() == team and tp.isAIPlayer():&lt;br /&gt;
                                aiplayer = tp&lt;br /&gt;
                                break&lt;br /&gt;
&lt;br /&gt;
                if aiplayer:&lt;br /&gt;
                        if p.getTeam() == 1: aiplayer.setTeam(2)&lt;br /&gt;
                        else: aiplayer.setTeam(1)&lt;br /&gt;
&lt;br /&gt;
        else:&lt;br /&gt;
                # checking to see if player is allowed to change teams&lt;br /&gt;
                team1 = 0&lt;br /&gt;
                team2 = 0&lt;br /&gt;
                for tp in bf2.playerManager.getPlayers():&lt;br /&gt;
                        if tp.getTeam() == 1: team1 += 1&lt;br /&gt;
                        else: team2 += 1&lt;br /&gt;
                if abs(team1 - team2) &amp;gt; 1:&lt;br /&gt;
                        if p.getTeam() == 1: p.setTeam(2)&lt;br /&gt;
                        else: p.setTeam(1)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==  Feautures  ==&lt;br /&gt;
&lt;br /&gt;
With all modifications you got a Autobalancescript with following Features:&lt;br /&gt;
&lt;br /&gt;
- Auto set Team 1 for Clanmembers on connect&lt;br /&gt;
- Protect Clanmembers from Autobalance&lt;br /&gt;
- Protect Commanders and Squadleaders from Autobalance&lt;br /&gt;
- Protect Squadmembers from Autobalance&lt;br /&gt;
&lt;br /&gt;
==  Feedback  ==&lt;br /&gt;
&lt;br /&gt;
You can give me a Feedback at nexus2kswiss(at)bs-dc.com&lt;br /&gt;
&lt;br /&gt;
--Nexus2k 06:02, 21 Jul 2005 (MDT)&lt;/div&gt;</summary>
		<author><name>Pireax</name></author>
	</entry>
	<entry>
		<id>https://bf2tech.uturista.pt/index.php?title=Scripts:Modified_admin_script&amp;diff=132</id>
		<title>Scripts:Modified admin script</title>
		<link rel="alternate" type="text/html" href="https://bf2tech.uturista.pt/index.php?title=Scripts:Modified_admin_script&amp;diff=132"/>
		<updated>2018-06-22T15:38:08Z</updated>

		<summary type="html">&lt;p&gt;Pireax: Created page with &amp;quot;__TOC__    == Introduction ==  When the BF2 server starts, it loads some code called an &amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;admin script&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;. The purpose of the default &amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;admin script&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039; provided by D...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
When the BF2 server starts, it loads some code called an &#039;&#039;&#039;&#039;&#039;admin script&#039;&#039;&#039;&#039;&#039;. The purpose of the default &#039;&#039;&#039;&#039;&#039;admin script&#039;&#039;&#039;&#039;&#039; provided by Dice, is to create and start an RCON service, letting both connected BF2 clients and standalone RCON clients run RCON commands on the server. The &#039;&#039;&#039;&#039;&#039;admin script&#039;&#039;&#039;&#039;&#039; is completely open to the server operator, and can be reprogrammed at will. It is located in the &#039;&#039;admin&#039;&#039; directory of the BF2 server, and the default &#039;&#039;&#039;&#039;&#039;admin script&#039;&#039;&#039;&#039;&#039; is called &#039;&#039;default.py&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
We at [http://www.battlefield.no/ Battlefield.no] have created a modified &#039;&#039;&#039;&#039;&#039;admin script&#039;&#039;&#039;&#039;&#039; that uses [http://www.multiplay.co.uk/ Steven Hartland&#039;s] brilliant idea of making the &#039;&#039;&#039;&#039;&#039;admin script&#039;&#039;&#039;&#039;&#039; load a separate configuration file, called &#039;&#039;adminsettings.con&#039;&#039;, from the same directory that the server has loaded the map list. These settings are loaded into a Python &#039;&#039;dictionary&#039;&#039; called &#039;&#039;options&#039;&#039;, and made globally available via a reference in the &#039;bf2&#039; object, calles &#039;&#039;adminoptions&#039;&#039;. The script also enables logging to both file and UDP, which are both configured using the &#039;&#039;adminsettings.con&#039;&#039; file. The &#039;&#039;adminsettings.con&#039;&#039; file is also re-read on every &#039;&#039;&#039;&#039;&#039;EndRound&#039;&#039;&#039;&#039;&#039; server event, so for most settings (RCON port and password being an exception) you do not have to restart the server to see the effect of a changed setting.&lt;br /&gt;
&lt;br /&gt;
== Getting Started ==&lt;br /&gt;
&lt;br /&gt;
No we&#039;ll have a look at what you need to do, to get online with the modified &#039;&#039;&#039;&#039;&#039;admin script&#039;&#039;&#039;&#039;&#039;. Please note that this description is for doing the modification on Linux. For Windows you will need to make some minor ajustments. Please see the &#039;&#039;discussion&#039;&#039; page for details.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Modifying the Admin Script ===&lt;br /&gt;
&lt;br /&gt;
It is not a good idea to modify the original &#039;&#039;default.py&#039;&#039;. It is much better to copy it, and start editing the copy. To enable your copy as the &#039;&#039;&#039;&#039;&#039;admin script&#039;&#039;&#039;&#039;&#039;, simply open the &#039;&#039;serversettings.con&#039;&#039; file that you are using, and edit the server setting called &#039;&#039;sv.adminScript&#039;&#039;, like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;sv.adminScript = &amp;quot;&amp;lt;name of admin script&amp;gt;&amp;quot; &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We at [http://www.battlefield.no/ Battlefield.no] have called our &#039;&#039;&#039;&#039;&#039;admin script&#039;&#039;&#039;&#039;&#039; &#039;&#039;bfno.py&#039;&#039;, and hence, our &#039;&#039;serversettings.con&#039;&#039; file is modified to look like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;sv.adminScript = &amp;quot;bfno&amp;quot; &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note the lack of the &#039;&#039;.py&#039;&#039; extension. You will need to change &#039;bfno&#039; to whatever you call your &#039;&#039;&#039;&#039;&#039;admin script&#039;&#039;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Creating the Admin Settings File ===&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;adminsettings.con&#039;&#039; file needs to reside in the same directory as your current &#039;&#039;maplist&#039;&#039;. So if you are starting your BF2 server without the &#039;&#039;+mapList&#039;&#039; option, you must place it in your &#039;&#039;mods/bf2/settings&#039;&#039; directory. When you have created it, you need to populate it with the following settings:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
admin.rconPort 4711&lt;br /&gt;
admin.rconPassword &amp;quot;yourRconPassword&amp;quot;&lt;br /&gt;
admin.debugLogEnabled 1&lt;br /&gt;
admin.debugLogFile &amp;quot;/path/to/debug.log&amp;quot;&lt;br /&gt;
admin.udpLogEnabled 1&lt;br /&gt;
admin.udpLogHost &amp;quot;localhost&amp;quot;&lt;br /&gt;
admin.udpLogPort 29500&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You will of course need to change the ports, path and password to your own, and turn off logging to file and/or UDP if you don&#039;t want that.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== The Admin Script ==&lt;br /&gt;
&lt;br /&gt;
This is the modified &#039;&#039;&#039;&#039;&#039;admin script&#039;&#039;&#039;&#039;&#039; as we use it at [http://www.battlefield.no/ Battlefield.no]. Feel free to copy it, and since this is a wiki, feel free to modify it. But we would be very gratefull of you appended a note in the &#039;&#039;updates&#039;&#039; section if you do.&lt;br /&gt;
&lt;br /&gt;
For your convenience, we&#039;ve uploaded the script to our website as well. You can download it [http://www.battlefield.no/filer/pafiledb.php?action=file&amp;amp;id=190 here]. &lt;br /&gt;
&lt;br /&gt;
=== The Code ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# Battlefield II -- default remote console module.&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
#&lt;br /&gt;
# This is a very simple, TCP based remote console which does simple MD5 digest&lt;br /&gt;
# password authentication. It can be configured via the admin/default.cfg file.&lt;br /&gt;
# Recognized options are &#039;port&#039; and &#039;password&#039;.&lt;br /&gt;
#&lt;br /&gt;
# Implementation guidelines for this file (and for your own rcon modules):&lt;br /&gt;
#&lt;br /&gt;
#  - All socket operations MUST be non-blocking. If your module blocks on a&lt;br /&gt;
#    socket the game server will hang.&lt;br /&gt;
#&lt;br /&gt;
#  - Do as little work as possible in update() as it runs in the server main&lt;br /&gt;
#    loop.&lt;br /&gt;
#&lt;br /&gt;
# Other notes:&lt;br /&gt;
#&lt;br /&gt;
#  - To get end-of-message markers (0x04 hex) after each reply, begin your&lt;br /&gt;
#    commands with an ascii 0x02 code. This module will then append the&lt;br /&gt;
#    end-of-message marker to all results. This is useful if you need to wait&lt;br /&gt;
#    for a complete response.&lt;br /&gt;
#&lt;br /&gt;
# Copyright (c)2004 Digital Illusions CE AB&lt;br /&gt;
# Author: Andreas `dep&#039; Fredriksson&lt;br /&gt;
#&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
#&lt;br /&gt;
# -----------------------------&lt;br /&gt;
# Changes made by the community&lt;br /&gt;
# -----------------------------&lt;br /&gt;
#&lt;br /&gt;
# If you make any modifications to this script that enhances its&lt;br /&gt;
# functionality, please post the changes to the ICCULUS mailing list.&lt;br /&gt;
#&lt;br /&gt;
# NB: Use &amp;quot;tab expansion&amp;quot;, and expand to 3 spaces!&lt;br /&gt;
#&lt;br /&gt;
# Maintained by Kybber and Panic, Battlefield.no.&lt;br /&gt;
#&lt;br /&gt;
# -----------&lt;br /&gt;
# Version 1.1&lt;br /&gt;
# -----------&lt;br /&gt;
#&lt;br /&gt;
# The script has been reorganized into the following sections:&lt;br /&gt;
# - Import&lt;br /&gt;
# - Variables&lt;br /&gt;
# - Classes&lt;br /&gt;
# - Functions&lt;br /&gt;
# - Program&lt;br /&gt;
#&lt;br /&gt;
# adminsettings.con:&lt;br /&gt;
# This version of the admin script uses this file for all admin&lt;br /&gt;
# settings. It is read and parsed by &#039;parseConfig&#039;. The file must&lt;br /&gt;
# be located in the same directory as the server is reading the&lt;br /&gt;
# maplist from.&lt;br /&gt;
#&lt;br /&gt;
# class writer:&lt;br /&gt;
# A heavily modified copy of the writer class has been added,&lt;br /&gt;
# facilitating logging to file and over udp.&lt;br /&gt;
#&lt;br /&gt;
# def parseConfig:&lt;br /&gt;
# The function parseConfig has been updated to load a file called&lt;br /&gt;
# adminsettings.con from the same directory as the maplist is being&lt;br /&gt;
# read. This emulates the old &amp;quot;+overlaypath&amp;quot; option. Thanks a lot to&lt;br /&gt;
# Steven Hartland at Multiplay.co.uk for this!&lt;br /&gt;
#&lt;br /&gt;
# def onGameStatusChanged:&lt;br /&gt;
# This function is built as a callback function to be registered with&lt;br /&gt;
# &#039;host.registerGameStatusHandler(onGameStatusChanged)&#039;. It&#039;s intended&lt;br /&gt;
# use is to reload the adminsettings.con file.&lt;br /&gt;
#&lt;br /&gt;
# This version of the file also &#039;globalizez&#039; the &#039;options&#039; dictionary,&lt;br /&gt;
# by adding a reference called &#039;adminoptions&#039; to the &#039;bf2&#039; object.&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
#                          I M P O R T&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
import socket&lt;br /&gt;
import errno&lt;br /&gt;
import host&lt;br /&gt;
import bf2&lt;br /&gt;
import types&lt;br /&gt;
import md5&lt;br /&gt;
import string&lt;br /&gt;
import random&lt;br /&gt;
import sys&lt;br /&gt;
import datetime&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
#                       V A R I A B L E S&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
# File version&lt;br /&gt;
version = &amp;quot;1.1&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Debug flags:&lt;br /&gt;
a_debug = 1 # Get debug info&lt;br /&gt;
a_info  = 1 # Get other runtime info&lt;br /&gt;
&lt;br /&gt;
# Admin options:&lt;br /&gt;
options = {&lt;br /&gt;
    &#039;admin.rconPort&#039;: &#039;4711&#039;,   # Overwritten by admin.rconPort in adminsettings.con&lt;br /&gt;
    &#039;admin.rconPassword&#039;: None, # Overwritten by admin.rconPassword in adminsettings.con&lt;br /&gt;
    # True if multiple commands should be processed in one update and&lt;br /&gt;
    # if as many responses as possible should be sent each update.&lt;br /&gt;
    &#039;admin.allowBatching&#039;: False,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
#                         C L A S S E S&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# class writer: Get a hold of stdout and stderr!&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
class writer:&lt;br /&gt;
   &amp;quot;&amp;quot;&amp;quot;Class for writing output to files and sockets&lt;br /&gt;
  &lt;br /&gt;
   Arguments&lt;br /&gt;
   The __init__ function takes no arguments.&lt;br /&gt;
&lt;br /&gt;
   Functions&lt;br /&gt;
   __init__(self) : Creating stream and socket objects to log to.&lt;br /&gt;
   __del__(self)  : Closes the streams and sockets created by __init__.&lt;br /&gt;
   write(self,str): Write data to the streams and sockets created by __init__.&lt;br /&gt;
&lt;br /&gt;
   Description&lt;br /&gt;
   The intended use of the class is to override sys.stdout and sys.stderr,&lt;br /&gt;
   like this: sys.stdout = sys.stderr = writer().&lt;br /&gt;
   &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
   # ---------------------------------------------------------------------&lt;br /&gt;
   # Constructor:&lt;br /&gt;
   # ---------------------------------------------------------------------&lt;br /&gt;
   def __init__(self):&lt;br /&gt;
      &amp;quot;&amp;quot;&amp;quot;Creates streams and sockets to log data to, using the write function.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
     &lt;br /&gt;
      # Class variables:&lt;br /&gt;
      self.debugLogEnabled = None&lt;br /&gt;
      self.debugLogFile = None&lt;br /&gt;
      self.udpLogEnabled = None&lt;br /&gt;
      self.udpLogHost = None&lt;br /&gt;
      self.udpLogPort = None&lt;br /&gt;
      self.stream = None&lt;br /&gt;
      self.sock = None&lt;br /&gt;
     &lt;br /&gt;
      # Try to get the debug log settings:&lt;br /&gt;
      try:&lt;br /&gt;
         if str(options[&#039;admin.debugLogEnabled&#039;]) in [&#039;True&#039;,&#039;true&#039;,&#039;1&#039;]: self.debugLogEnabled = True&lt;br /&gt;
         self.debugLogFile = options[&#039;admin.debugLogFile&#039;]&lt;br /&gt;
      except:&lt;br /&gt;
         pass&lt;br /&gt;
      # Try to get the udp log settings:&lt;br /&gt;
      try:&lt;br /&gt;
         if str(options[&#039;admin.udpLogEnabled&#039;]) in [&#039;True&#039;,&#039;true&#039;,&#039;1&#039;]: self.udpLogEnabled = True&lt;br /&gt;
         self.udpLogHost = str(options[&#039;admin.udpLogHost&#039;])&lt;br /&gt;
         self.udpLogPort = int(options[&#039;admin.udpLogPort&#039;])&lt;br /&gt;
      except:&lt;br /&gt;
         pass&lt;br /&gt;
     &lt;br /&gt;
      # Prepare for udp logging:&lt;br /&gt;
      if self.udpLogEnabled and self.udpLogHost and self.udpLogPort:&lt;br /&gt;
         self.sock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)&lt;br /&gt;
     &lt;br /&gt;
      # Prepare for logging to file:&lt;br /&gt;
      if self.debugLogEnabled and self.debugLogFile:&lt;br /&gt;
         self.stream = open( self.debugLogFile, &#039;a+&#039; )&lt;br /&gt;
&lt;br /&gt;
   # ---------------------------------------------------------------------&lt;br /&gt;
  &lt;br /&gt;
   # ---------------------------------------------------------------------&lt;br /&gt;
   # Deconstructor:&lt;br /&gt;
   # ---------------------------------------------------------------------&lt;br /&gt;
   def __del__(self):&lt;br /&gt;
      &amp;quot;&amp;quot;&amp;quot;Closes the streams and sockets created by __init__&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
      if self.stream: self.stream.close()&lt;br /&gt;
      if self.sock: self.sock.close()&lt;br /&gt;
   # ---------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
   # ---------------------------------------------------------------------&lt;br /&gt;
   # Write data:&lt;br /&gt;
   # ---------------------------------------------------------------------&lt;br /&gt;
   &amp;quot;&amp;quot;&amp;quot;Writes data to the streams and sockets defined in __init__&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
   def write(self, str):&lt;br /&gt;
      if &#039;\n&#039; != str:&lt;br /&gt;
         if self.stream: self.stream.write(&#039;[&#039; + datetime.datetime.now().strftime(&amp;quot;%Y-%m-%d %H:%M:%S&amp;quot;)  + &#039;] &#039; + str)&lt;br /&gt;
         if self.sock: self.sock.sendto(str,(self.udpLogHost,self.udpLogPort))&lt;br /&gt;
      else:&lt;br /&gt;
         if self.stream:&lt;br /&gt;
            self.stream.write(str)&lt;br /&gt;
            self.stream.flush()&lt;br /&gt;
   # ---------------------------------------------------------------------&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# A stateful output buffer that knows how to enqueue data and ship it out&lt;br /&gt;
# without blocking.&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
class OutputBuffer(object):&lt;br /&gt;
&lt;br /&gt;
    def __init__(self, sock):&lt;br /&gt;
        self.sock = sock&lt;br /&gt;
        self.data = []&lt;br /&gt;
        self.index = 0&lt;br /&gt;
&lt;br /&gt;
    def enqueue(self, str):&lt;br /&gt;
        self.data.append(str)&lt;br /&gt;
&lt;br /&gt;
    def update(self):&lt;br /&gt;
        allowBatching = options[&#039;admin.allowBatching&#039;]&lt;br /&gt;
        while len(self.data) &amp;gt; 0:&lt;br /&gt;
            try:&lt;br /&gt;
                item = self.data[0]&lt;br /&gt;
                scount = self.sock.send(item[self.index:])&lt;br /&gt;
                self.index += scount&lt;br /&gt;
                if self.index == len(item):&lt;br /&gt;
                    del self.data[0]&lt;br /&gt;
                    self.index = 0&lt;br /&gt;
            except socket.error, detail:&lt;br /&gt;
                if detail[0] != errno.EWOULDBLOCK:&lt;br /&gt;
                    return detail[1]&lt;br /&gt;
            if not allowBatching:&lt;br /&gt;
                break&lt;br /&gt;
        return None&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# Each TCP connection is represented by an object of this class.&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
class AdminConnection(object):&lt;br /&gt;
&lt;br /&gt;
    def __init__(self, srv, sock, addr):&lt;br /&gt;
        print &#039;new rcon/admin connection from %s:%d&#039; % (addr[0], addr[1])&lt;br /&gt;
        self.server = srv&lt;br /&gt;
        self.sock = sock&lt;br /&gt;
        self.addr = addr&lt;br /&gt;
        self.sock.setblocking(0)&lt;br /&gt;
        self.buffer = &#039;&#039;&lt;br /&gt;
        self.seed = make_seed(16)&lt;br /&gt;
        self.correct_digest = digest(self.seed, options[&#039;admin.rconPassword&#039;])&lt;br /&gt;
        self.outbuf = OutputBuffer(self.sock)&lt;br /&gt;
       &lt;br /&gt;
        # Welcome message *must* end with \n\n&lt;br /&gt;
        self.outbuf.enqueue(&#039;### Battlefield 2 default RCON/admin ready.\n&#039;)&lt;br /&gt;
        self.outbuf.enqueue(&#039;### Digest seed: %s\n&#039; % (self.seed))&lt;br /&gt;
        self.outbuf.enqueue(&#039;\n&#039;) # terminate welcome message with extra LF&lt;br /&gt;
&lt;br /&gt;
    def update(self):&lt;br /&gt;
        err = None&lt;br /&gt;
        try:&lt;br /&gt;
            allowBatching = options[&#039;admin.allowBatching&#039;]&lt;br /&gt;
            while not err:&lt;br /&gt;
                data = self.sock.recv(1024)&lt;br /&gt;
                if data:&lt;br /&gt;
                    self.buffer += data&lt;br /&gt;
                    while not err:&lt;br /&gt;
                        nlpos = self.buffer.find(&#039;\n&#039;)&lt;br /&gt;
                        if nlpos != -1:&lt;br /&gt;
                            self.server.onRemoteCommand(self, self.buffer[0:nlpos])&lt;br /&gt;
                            self.buffer = self.buffer[nlpos+1:] # keep rest of buffer&lt;br /&gt;
                        else:&lt;br /&gt;
                            if len(self.buffer) &amp;gt; 128:&lt;br /&gt;
                                err = &#039;data format error: no newline in message&#039;&lt;br /&gt;
                            break&lt;br /&gt;
                        if not allowBatching: break&lt;br /&gt;
                else:&lt;br /&gt;
                    err = &#039;peer disconnected&#039;&lt;br /&gt;
               &lt;br /&gt;
                if not allowBatching: break&lt;br /&gt;
&lt;br /&gt;
        except socket.error, detail:&lt;br /&gt;
            if detail[0] != errno.EWOULDBLOCK:&lt;br /&gt;
                err = detail[1]&lt;br /&gt;
&lt;br /&gt;
        if not err:&lt;br /&gt;
            err = self.outbuf.update()&lt;br /&gt;
&lt;br /&gt;
        if err:&lt;br /&gt;
            print &#039;rcon: closing %s:%d: %s&#039; % (self.addr[0], self.addr[1], err)&lt;br /&gt;
            try:&lt;br /&gt;
                self.sock.shutdown(2)&lt;br /&gt;
                self.sock.close()&lt;br /&gt;
            except:&lt;br /&gt;
                print &#039;rcon: warning: failed to close %s&#039; % (self.addr)&lt;br /&gt;
                pass&lt;br /&gt;
            return 0&lt;br /&gt;
        else:&lt;br /&gt;
            return 1&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# Context passed to remote command implementations for them to write output to&lt;br /&gt;
# either a remote tcp socket or an in-game client executing &#039;rcon &amp;lt;command&amp;gt;&#039;.&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
class CommandContext(object):&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        self.player = None&lt;br /&gt;
        self.socket = None&lt;br /&gt;
        self.output = []&lt;br /&gt;
&lt;br /&gt;
    def isInGame(self): return self.player is not None&lt;br /&gt;
    def isSocket(self): return self.socket is not None&lt;br /&gt;
    def write(self, text): self.output.append(text)&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# The server itself.&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
class AdminServer(object):&lt;br /&gt;
&lt;br /&gt;
    def __init__(self, port):&lt;br /&gt;
        # state for tcp rcon connections&lt;br /&gt;
        self.port = port&lt;br /&gt;
        self.backlog = 1&lt;br /&gt;
        self.peers = []&lt;br /&gt;
        self.openSocket()&lt;br /&gt;
&lt;br /&gt;
        # state for in-game rcon connections&lt;br /&gt;
        host.registerHandler(&#039;RemoteCommand&#039;, self.onRemoteCommand, 1)&lt;br /&gt;
        host.registerHandler(&#039;PlayerDisconnect&#039;, self.onPlayerDisconnect, 1)&lt;br /&gt;
        host.registerHandler(&#039;ChatMessage&#039;, self.onChatMessage, 1)&lt;br /&gt;
&lt;br /&gt;
        # contains player ids for players which have successfully authenticated&lt;br /&gt;
        # themselves with &#039;rcon login &amp;lt;passwd&amp;gt;&#039;&lt;br /&gt;
        self.authed_players = {}&lt;br /&gt;
        # contains sockets for connections which have successfully authenticated&lt;br /&gt;
        # themselves with &#039;login &amp;lt;passwd&amp;gt;&#039;&lt;br /&gt;
        self.authed_sockets = {}&lt;br /&gt;
&lt;br /&gt;
        # rcon commands supported in this vanilla version&lt;br /&gt;
        self.rcon_cmds = {&lt;br /&gt;
            &#039;login&#039;: self.rcmd_login,&lt;br /&gt;
            &#039;users&#039;: self.rcmd_users,&lt;br /&gt;
            &#039;exec&#039;: self.rcmd_exec&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
    # Called when a user types &#039;rcon &#039; followed by any string in a client&lt;br /&gt;
    # console window or when a TCP client sends a complete line to be&lt;br /&gt;
    # evaluated.&lt;br /&gt;
    def onRemoteCommand(self, playerid_or_socket, cmd):&lt;br /&gt;
        cmd = cmd.strip()&lt;br /&gt;
        interactive = True&lt;br /&gt;
&lt;br /&gt;
        # Is this a non-interactive client?&lt;br /&gt;
        if len(cmd) &amp;gt; 0 and cmd[0] == &#039;\x02&#039;:&lt;br /&gt;
            cmd = cmd[1:]&lt;br /&gt;
            interactive = False&lt;br /&gt;
&lt;br /&gt;
        spacepos = cmd.find(&#039; &#039;)&lt;br /&gt;
        if spacepos == -1: spacepos=len(cmd)&lt;br /&gt;
        subcmd = cmd[0:spacepos]&lt;br /&gt;
&lt;br /&gt;
        ctx = CommandContext()&lt;br /&gt;
        authed = 0&lt;br /&gt;
        if type(playerid_or_socket) == types.IntType:&lt;br /&gt;
            ctx.player = playerid_or_socket&lt;br /&gt;
            authed = self.authed_players.has_key(ctx.player)&lt;br /&gt;
        else:&lt;br /&gt;
            ctx.socket = playerid_or_socket&lt;br /&gt;
            authed = self.authed_sockets.has_key(ctx.socket)&lt;br /&gt;
           &lt;br /&gt;
        # you can only login unless you are authenticated&lt;br /&gt;
        if subcmd != &#039;login&#039; and not authed:&lt;br /&gt;
            ctx.write(&#039;error: not authenticated: you can only invoke \&#039;login\&#039;\n&#039;)&lt;br /&gt;
        else:&lt;br /&gt;
            if self.rcon_cmds.has_key(subcmd):&lt;br /&gt;
                self.rcon_cmds[subcmd](ctx, cmd[spacepos+1:])&lt;br /&gt;
            else:&lt;br /&gt;
                ctx.write(&#039;unknown command: \&#039;%s\&#039;\n&#039; % (subcmd))&lt;br /&gt;
&lt;br /&gt;
        feedback = &#039;&#039;.join(ctx.output)&lt;br /&gt;
        if ctx.socket:&lt;br /&gt;
            if interactive:&lt;br /&gt;
                ctx.socket.outbuf.enqueue(feedback)&lt;br /&gt;
            else:&lt;br /&gt;
                ctx.socket.outbuf.enqueue(feedback + &#039;\x04&#039;)&lt;br /&gt;
        else:&lt;br /&gt;
            host.rcon_feedback(ctx.player, feedback)&lt;br /&gt;
&lt;br /&gt;
    # When players disconnect, remove them from the auth map if they were&lt;br /&gt;
    # authenticated so that the next user with the same id doesn&#039;t get rcon&lt;br /&gt;
    # access.&lt;br /&gt;
    def onPlayerDisconnect(self, player_id):&lt;br /&gt;
        if self.authed_players.has_key(player_id):&lt;br /&gt;
            del self.authed_players[player_id]&lt;br /&gt;
&lt;br /&gt;
    # Called whenever a player issues a chat string.&lt;br /&gt;
    def onChatMessage(self, player_id, text, channel, flags):&lt;br /&gt;
        print &#039;chat: pid=%d text=\&#039;%s\&#039; channel=%s&#039; % (player_id, text, channel)&lt;br /&gt;
&lt;br /&gt;
    # Sets up the listening TCP RCON socket. This binds to 0.0.0.0, which may&lt;br /&gt;
    # not be what you want but it&#039;s a sane default for most installations.&lt;br /&gt;
    def openSocket(self):&lt;br /&gt;
        try:&lt;br /&gt;
            self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)&lt;br /&gt;
            #self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, 0)&lt;br /&gt;
            #self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)&lt;br /&gt;
            self.sock.bind((&#039;0.0.0.0&#039;, self.port))&lt;br /&gt;
            self.sock.listen(self.backlog)&lt;br /&gt;
            self.sock.setblocking(0)&lt;br /&gt;
        except socket.error, detail:&lt;br /&gt;
            print &#039;failed to bind rcon socket--only in-game rcon will be enabled&#039;&lt;br /&gt;
&lt;br /&gt;
    # WARNING: update is called very frequently -- don&#039;t go crazy with logic&lt;br /&gt;
    # here.&lt;br /&gt;
    def update(self):&lt;br /&gt;
        # if we don&#039;t have a socket, just return&lt;br /&gt;
        if not self.sock: return&lt;br /&gt;
&lt;br /&gt;
        # without blocking, check for new connections&lt;br /&gt;
        try:&lt;br /&gt;
            conn, peeraddr = self.sock.accept()&lt;br /&gt;
            self.peers.append(AdminConnection(self, conn, peeraddr))&lt;br /&gt;
        except socket.error, detail:&lt;br /&gt;
            if detail[0] != errno.EWOULDBLOCK:&lt;br /&gt;
                raise socket.error, detail&lt;br /&gt;
&lt;br /&gt;
        # update clients and mark connections that fail their update&lt;br /&gt;
        disc = []&lt;br /&gt;
        for client in self.peers:&lt;br /&gt;
            if not client.update(): disc.append(client)&lt;br /&gt;
&lt;br /&gt;
        # delete any auth status for closed tcp connections&lt;br /&gt;
        for d in disc:&lt;br /&gt;
            if self.authed_sockets.has_key(d): del self.authed_sockets[d]&lt;br /&gt;
&lt;br /&gt;
        # now keep the remaining clients&lt;br /&gt;
        self.peers = filter(lambda x: x not in disc, self.peers)&lt;br /&gt;
&lt;br /&gt;
    def shutdown(self):&lt;br /&gt;
        if self.sock:&lt;br /&gt;
            self.sock.close()&lt;br /&gt;
&lt;br /&gt;
    # Command implementations go here (member functions of the AdminServer)&lt;br /&gt;
&lt;br /&gt;
    # Allows a in-game rcon client to authenticate and get access.&lt;br /&gt;
    def rcmd_login(self, ctx, cmd):&lt;br /&gt;
        success = 0&lt;br /&gt;
        if ctx.isInGame():&lt;br /&gt;
            # We&#039;re called by an in-game rcon client, use plain-text password&lt;br /&gt;
            # (encoded into bf2 network stream).&lt;br /&gt;
            if cmd.strip() == options[&#039;admin.rconPassword&#039;]:&lt;br /&gt;
                    self.authed_players[ctx.player] = 1&lt;br /&gt;
                    success = 1&lt;br /&gt;
            elif self.authed_players.has_key(ctx.player):&lt;br /&gt;
                    del self.authed_players[ctx.player]&lt;br /&gt;
        else:&lt;br /&gt;
            # tcp client, require seeded digest to match instead of pw&lt;br /&gt;
            if cmd.strip() == ctx.socket.correct_digest:&lt;br /&gt;
                self.authed_sockets[ctx.socket] = 1&lt;br /&gt;
                print &#039;rcon: tcp client from %s:%d logged on&#039; % ctx.socket.addr&lt;br /&gt;
                success = 1&lt;br /&gt;
            else:&lt;br /&gt;
                if self.authed_sockets.has_key(ctx.socket):&lt;br /&gt;
                    del self.authed_sockets[ctx.socket]&lt;br /&gt;
                print &#039;rcon: tcp client from %s:%d failed pw challenge&#039; % ctx.socket.addr&lt;br /&gt;
&lt;br /&gt;
        if success:&lt;br /&gt;
            ctx.write(&#039;Authentication successful, rcon ready.\n&#039;)&lt;br /&gt;
        else:&lt;br /&gt;
            ctx.write(&#039;Authentication failed.\n&#039;)&lt;br /&gt;
&lt;br /&gt;
    # Lists rcon-authenticated players.&lt;br /&gt;
    def rcmd_users(self, ctx, cmd):&lt;br /&gt;
        ctx.write(&#039;active rcon users:\n&#039;)&lt;br /&gt;
        for id in self.authed_players:&lt;br /&gt;
            if id == -1:&lt;br /&gt;
                ctx.write(&#039;-1 (local server console)\n&#039;)&lt;br /&gt;
            else:&lt;br /&gt;
                try:&lt;br /&gt;
                    player = bf2.playerManager.getPlayerByIndex(id)&lt;br /&gt;
                except:&lt;br /&gt;
                    ctx.write(&#039;%d (no info)\n&#039; % (id))&lt;br /&gt;
&lt;br /&gt;
        for peer in self.authed_sockets:&lt;br /&gt;
            ctx.write(&#039;tcp: %s:%d\n&#039; % (peer.addr[0], peer.addr[1]))&lt;br /&gt;
&lt;br /&gt;
    # Executes a console command on the server.&lt;br /&gt;
    def rcmd_exec(self, ctx, cmd):&lt;br /&gt;
        ctx.write(host.rcon_invoke(cmd))&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
#                         F U N C T I O N S&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# These functions are called from the engine&lt;br /&gt;
# We implement them in terms of a class instance:&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
def init():&lt;br /&gt;
    print &#039;initializing default admin/rcon module&#039;&lt;br /&gt;
   &lt;br /&gt;
    # load (optional) admin scripts like teamkill punish and autobalance&lt;br /&gt;
    import standard_admin&lt;br /&gt;
&lt;br /&gt;
def shutdown():&lt;br /&gt;
    if server:&lt;br /&gt;
        print &#039;shutting down default admin/rcon module&#039;&lt;br /&gt;
        server.shutdown()&lt;br /&gt;
&lt;br /&gt;
def update():&lt;br /&gt;
    if server: server.update()&lt;br /&gt;
   # NB: Use with care!&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# Returns a seed string of random characters to be used as a salt&lt;br /&gt;
# to protect password sniffing.&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
def make_seed(seed_length):&lt;br /&gt;
    return &#039;&#039;.join([string.ascii_letters[random.randint(0, len(string.ascii_letters)-1)] for x in xrange(0, seed_length)])&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# Concats a seed string with the password and returns an ASCII-hex MD5 digest.&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
def digest(seed, pw):&lt;br /&gt;
    if not pw: return None&lt;br /&gt;
    m = md5.new()&lt;br /&gt;
    m.update(seed)&lt;br /&gt;
    m.update(pw)&lt;br /&gt;
    return m.hexdigest()&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ---------------------------------------------------------------------&lt;br /&gt;
# Convert string to boolean:&lt;br /&gt;
# ---------------------------------------------------------------------&lt;br /&gt;
def boolFromString(str):&lt;br /&gt;
   &amp;quot;&amp;quot;&amp;quot;Returns a true boolean value based on a boolean string&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
   str = str(str)&lt;br /&gt;
   if str in [&#039;True&#039;, &#039;true&#039;, &#039;1&#039;]:&lt;br /&gt;
      return True&lt;br /&gt;
   elif value in [&#039;False&#039;, &#039;false&#039;, &#039;0&#039;]:&lt;br /&gt;
      return False&lt;br /&gt;
   else:&lt;br /&gt;
      #raise ValueError # Never mind errors...&lt;br /&gt;
      return False&lt;br /&gt;
# ---------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# Parses the config file, if it&#039;s there&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
def parseConfig( file ):&lt;br /&gt;
   &amp;quot;&amp;quot;&amp;quot;Function for loading a settings file&lt;br /&gt;
&lt;br /&gt;
   Arguments&lt;br /&gt;
   file: Path to the file to load&lt;br /&gt;
&lt;br /&gt;
   Description&lt;br /&gt;
   This function load a file with key-value-pairs on the form &#039;key = value&#039;,&lt;br /&gt;
   and updates the dictionary &#039;options&#039; accordingly.&lt;br /&gt;
   &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
   if a_info: print &amp;quot;ADMIN: Loading &#039;%s&#039;&amp;quot; % ( file )&lt;br /&gt;
&lt;br /&gt;
   try:&lt;br /&gt;
      config = open(file, &#039;r&#039;)&lt;br /&gt;
      lineNo = 0&lt;br /&gt;
      for line in config:&lt;br /&gt;
         lineNo += 1&lt;br /&gt;
         if line.strip() != &#039;&#039; and line.strip() != &#039;\n&#039;:&lt;br /&gt;
            try:&lt;br /&gt;
               ( key, value ) = line.split( &#039; &#039;, 1 )&lt;br /&gt;
               # remove white space&lt;br /&gt;
               value = value.strip()&lt;br /&gt;
               # remove outer quotes&lt;br /&gt;
               value = value.strip( &#039;&amp;quot;&#039; )&lt;br /&gt;
              &lt;br /&gt;
               if a_info: print &amp;quot;ADMIN: setting &#039;%s&#039; = &#039;%s&#039;&amp;quot; % ( key, value )&lt;br /&gt;
               if value == &#039;allowBatching&#039;: value = boolFromString (value)&lt;br /&gt;
               options[key] = value&lt;br /&gt;
&lt;br /&gt;
            except ValueError:&lt;br /&gt;
               if a_debug or a_info: print &#039;ADMIN: WARNING - syntax error in &amp;quot;%s&amp;quot; on line %d&#039; % (file, lineNo)&lt;br /&gt;
   except IOError, detail:&lt;br /&gt;
      if a_debug or a_info: print &#039;ADMIN: WARNING - couldn\&#039;t read &amp;quot;%s&amp;quot;: %s&#039; % (file, detail)&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# Put stuff you need done by the end of round here&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
def onGameStatusChanged(status):&lt;br /&gt;
   &amp;quot;&amp;quot;&amp;quot;Handles changes in game status.&lt;br /&gt;
&lt;br /&gt;
   Arguments&lt;br /&gt;
   status: Integer indicating game status. (see bf2.GameStatus.*)&lt;br /&gt;
&lt;br /&gt;
   Description&lt;br /&gt;
   This function is registered with the server with host.registerGameStatusHandler(onGameStatusChanged),&lt;br /&gt;
   and its intended use is to reload adminsettnigs at the end of rounds, and other, similar tasks.&lt;br /&gt;
   &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
   global adminSettingsFile&lt;br /&gt;
   if a_debug: print &amp;quot;ADMIN: Entering onGameStatusChanged (&amp;quot; + str(status) +&amp;quot;)&amp;quot;&lt;br /&gt;
   if status == bf2.GameStatus.EndGame:&lt;br /&gt;
      parseConfig(adminSettingsFile)&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
#                        P R O G R A M&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# Globalize the admin options:&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
bf2.adminoptions = options&lt;br /&gt;
# Now other scripts might benefit from the settings stored in the&lt;br /&gt;
# adminsettings.con file!&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# Load admin settings:&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# Figure out the &amp;quot;overlay&amp;quot; path:&lt;br /&gt;
mapListFileParts = host.rcon_invoke( &#039;mapList.configFile&#039; ).split( &#039;/&#039; );&lt;br /&gt;
del mapListFileParts[len( mapListFileParts ) - 1]&lt;br /&gt;
profileDir = &amp;quot;/&amp;quot;.join( mapListFileParts )&lt;br /&gt;
# Set the full path to our admin settings file:&lt;br /&gt;
adminSettingsFile = profileDir + &amp;quot;/adminsettings.con&amp;quot;&lt;br /&gt;
# parse the configuration file&lt;br /&gt;
parseConfig( adminSettingsFile )&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# Register handlers:&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# Monitor game status:&lt;br /&gt;
host.registerGameStatusHandler(onGameStatusChanged)&lt;br /&gt;
# NB: &#039;onGameStatusChanged&#039; uses the variable &#039;adminSettingsFile&#039;!&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# Enable debug logging:&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
if a_debug or a_info: sys.stdout = sys.stderr = writer()&lt;br /&gt;
print &amp;quot;Logging enabled&amp;quot;&lt;br /&gt;
print &amp;quot;Starting rcon on port %s&amp;quot; % ( options[&#039;admin.rconPort&#039;] )&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# Start the RCON server:&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
server = AdminServer(int(options[&#039;admin.rconPort&#039;]))&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Updates ==&lt;br /&gt;
&lt;br /&gt;
Please add a note here if you update the code above.&lt;br /&gt;
&lt;br /&gt;
* 2005-06-18: Added documentation (Panic)&lt;br /&gt;
* 2005-06-17: Added v1.1 of the code (Panic)&lt;/div&gt;</summary>
		<author><name>Pireax</name></author>
	</entry>
	<entry>
		<id>https://bf2tech.uturista.pt/index.php?title=Scripts:Enhanced_rotate_demo&amp;diff=131</id>
		<title>Scripts:Enhanced rotate demo</title>
		<link rel="alternate" type="text/html" href="https://bf2tech.uturista.pt/index.php?title=Scripts:Enhanced_rotate_demo&amp;diff=131"/>
		<updated>2018-06-22T15:37:46Z</updated>

		<summary type="html">&lt;p&gt;Pireax: Created page with &amp;quot;__TOC__  == Enhancements ==  &amp;lt;pre&amp;gt;  July 14, 2005 Enhanced rotate_demo.py by: Dave Lawrence  thrash@fragnastika.com Includes updates by: dackz &amp;lt;/pre&amp;gt;  &amp;lt;pre&amp;gt; Changes - Fixed ap...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== Enhancements ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 July 14, 2005&lt;br /&gt;
Enhanced rotate_demo.py&lt;br /&gt;
by: Dave Lawrence  thrash@fragnastika.com&lt;br /&gt;
Includes updates by: dackz&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Changes&lt;br /&gt;
- Fixed apparent issue where FTP credentials require use of &#039;@&#039; (at least in Win)&lt;br /&gt;
- Added grossly verbose error logging for troubleshooting FTP problems&lt;br /&gt;
- Added cfg option &amp;quot;verbose_log&amp;quot; to enable verbose logging&lt;br /&gt;
- Added verbose log file &amp;quot;rotate_demo_log.txt&amp;quot;&lt;br /&gt;
  * For console debugging, set verbose_log=0  to log to the console&lt;br /&gt;
- Incorporated local file mods by dackz&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Usage:&lt;br /&gt;
- In Windows it is recommended to use the compiled version of this tool&lt;br /&gt;
- In ServerSettings.con you would use something like the following&lt;br /&gt;
-        sv.autoDemoHook &amp;quot;adminutils/demo/rotate_demo.exe&amp;quot;&lt;br /&gt;
- If you did not receive the exe version of this script, you can compile by:&lt;br /&gt;
   * Download ActivePython v2.4       &lt;br /&gt;
   * Install ActivePython&lt;br /&gt;
   * Download py2exe for Python v2.4!&lt;br /&gt;
   * Install py2exe&lt;br /&gt;
   * Place the Enhanced rotate_demo.py in AdminUtils\demo&lt;br /&gt;
   * From the cmd prompt (with python in your PATH), run:&lt;br /&gt;
       python setup.py py2exe&lt;br /&gt;
   * py2exe should execute and create a directory: dist&lt;br /&gt;
   * AdminUtils\demo\dist contains rotate_demo.exe&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Downloads [http://activestate.com/ http://activestate.com] &amp;lt;s&amp;gt;[http://starship.python.net/crew/theller/py2exe http://starship.python.net/crew/theller/py2exe]&amp;lt;/s&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Installation  ==&lt;br /&gt;
&lt;br /&gt;
# Browse to &amp;lt;code&amp;gt;adminutils/demo/&amp;lt;/code&amp;gt; in your bf2 server directory&lt;br /&gt;
# Backup &amp;lt;code&amp;gt;rotate_demo.py&amp;lt;/code&amp;gt;. (&amp;lt;code&amp;gt;cp rotate_demo.py rotate_demo.py.bak&amp;lt;/code&amp;gt;.)&lt;br /&gt;
# Download rotate_demo.py or copy the below text into a file manually.&lt;br /&gt;
# If necessary, download the exe and locate in the same place&lt;br /&gt;
&lt;br /&gt;
== Operation  ==&lt;br /&gt;
&lt;br /&gt;
=== General  ===&lt;br /&gt;
&lt;br /&gt;
By default, a log file called rotate_demo_log.txt will created that logs the actions from the prior execution. When there is an error, you can view each operation that completed prio to the error as well as the eeor itself in this file. In addition, rotate_demo_err.txt still clumsily records the same info it did before.&lt;br /&gt;
&lt;br /&gt;
If you are having problems getting the demo moved the appropriate place, I strongly recommend that you run the script manualy from the command line, and outside of the game. The script takes one parameter which is the filename of the demo file. This filename can be of any file. IF you want to check the rotation features, just make sure the test files end with &amp;quot;.bf2demo&amp;quot; for example&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd /games/bf2&lt;br /&gt;
touch test1.bf2demo&lt;br /&gt;
python AdminUtils/demo/rotate_demo.py test1.bf2demo&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It is *much* easier to debug this way.&lt;br /&gt;
&lt;br /&gt;
=== Win BF2 and FTP  ===&lt;br /&gt;
&lt;br /&gt;
For some reason I cannot get the rotate_demo.py script to execute properly under a Windows BF2 server using FTP with an FTP username that use a &amp;quot;@&amp;quot;. A popular convention on at least cPanel web hosters is to include the server domain name along with the username, separate with &amp;quot;@&amp;quot;. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Host: files.myhost.com&lt;br /&gt;
User: myhoster@myhost.com&lt;br /&gt;
 Pwd: blahblah&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With a username as shown above, under Windows, the BF2 server is just not parsing the username correctly and the FTP fails. I have no idea why, although it must have something to do with the BF2 version Python. In any case, if you are using Windows, and you have an FTP username like this, I recommend using the compiled version of this script, rotate_demo.exe. This will work.&lt;br /&gt;
&lt;br /&gt;
== Code  ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Downloadable  ===&lt;br /&gt;
&lt;br /&gt;
These urls are out of date and no longer available&lt;br /&gt;
&lt;br /&gt;
The source &amp;lt;s&amp;gt;[http://files.fragnastika.net/bf2_rotate_demo/Enhanced/rotate_demo.py http://files.fragnastika.net/bf2_rotate_demo/Enhanced/rotate_demo.py]&amp;lt;/s&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The Win exe version &amp;lt;s&amp;gt;[http://files.fragnastika.net/bf2_rotate_demo/Enhanced/rotate_demo.exe http://files.fragnastika.net/bf2_rotate_demo/Enhanced/rotate_demo.exe]&amp;lt;/s&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Readable  ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#! /usr/bin/python&lt;br /&gt;
#&lt;br /&gt;
# rotate_demo.py: simple file-rotation and index updating script&lt;br /&gt;
#&lt;br /&gt;
# Requires Python 2.3 or newer.&lt;br /&gt;
#&lt;br /&gt;
# Theory of operation:&lt;br /&gt;
# When automatic demo recording is enabled in the BF2 dedicated server it will&lt;br /&gt;
# call a hook program (such as this) when a new demo file is ready for&lt;br /&gt;
# publishing. The server will wait for the hook program to complete before&lt;br /&gt;
# notifying connected clients of the URL the demo can be downloaded from. It is&lt;br /&gt;
# therefore important that all work is done in a blocking manner in this&lt;br /&gt;
# program, or clients might try to download demos that aren&#039;t in place on the&lt;br /&gt;
# web server yet.&lt;br /&gt;
#&lt;br /&gt;
# Copyright (c)2004 Digital Illusions CE AB&lt;br /&gt;
# Author: Andreas Fredriksson&lt;br /&gt;
&lt;br /&gt;
#&lt;br /&gt;
# July 14, 2005&lt;br /&gt;
# Enhanced rotate_demo.py&lt;br /&gt;
# by: Dave Lawrence  thrash@fragnastika.com&lt;br /&gt;
# Includes updates by: dackz&lt;br /&gt;
#&lt;br /&gt;
# Changes&lt;br /&gt;
# - Fixed apparent issue where FTP credentials require use of &#039;@&#039;&lt;br /&gt;
# - Added grossly verbose error logging for troubleshooting FTP problems&lt;br /&gt;
# - Added cfg option &amp;quot;verbose_log&amp;quot; to enable verbose logging&lt;br /&gt;
# - Added verbose log file &amp;quot;rotate_demo_log.txt&amp;quot;&lt;br /&gt;
#   * For console debugging, set verbose_log=0  to log to the console&lt;br /&gt;
# - Incorporated local file mods by dackz&lt;br /&gt;
#&lt;br /&gt;
# Usage:&lt;br /&gt;
# - In Windows it is recommended to use the compiled version of this tool&lt;br /&gt;
# - In ServerSettings.con you would use something like the following&lt;br /&gt;
#        sv.autoDemoHook &amp;quot;adminutils/demo/rotate_demo.exe&amp;quot;&lt;br /&gt;
# - If you did not receive the exe version of this script, you can compile by:&lt;br /&gt;
#        * Download ActivePython v2.41 from http://activestate.com&lt;br /&gt;
#        * Install ActivePython&lt;br /&gt;
#        * Download py2exe from http://starship.python.net/crew/theller/py2exe  VERSION 2.4!&lt;br /&gt;
#        * Install py2exe&lt;br /&gt;
#         * Place the Enhanced rotate_demo.py in AdminUtils\demo&lt;br /&gt;
#        * From the cmd prompt (with python in your PATH), run:&lt;br /&gt;
#            python setup.py py2exe&lt;br /&gt;
#        * py2exe should execute and create a directory: dist&lt;br /&gt;
#        * AdminUtils\demo\dist contains rotate_demo.exe&lt;br /&gt;
#&lt;br /&gt;
&lt;br /&gt;
import os&lt;br /&gt;
import sys&lt;br /&gt;
import shutil&lt;br /&gt;
&lt;br /&gt;
# for debugging a hack like this might be useful since stdout and stderr are&lt;br /&gt;
# discarded when the script is run&lt;br /&gt;
class writer:&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        self.stream = open(&#039;rotate_demo_log.txt&#039;, &#039;w&#039;)&lt;br /&gt;
    def write(self, str):&lt;br /&gt;
        self.stream.write(str)&lt;br /&gt;
&lt;br /&gt;
# helper function to create directories as needed -- this doesn&#039;t care about&lt;br /&gt;
# umask or permissions in general so consider this a starting point&lt;br /&gt;
def ensure_exists(path):&lt;br /&gt;
    try:&lt;br /&gt;
        os.stat(path)&lt;br /&gt;
    except:&lt;br /&gt;
        try:&lt;br /&gt;
            os.makedirs(path)&lt;br /&gt;
        except:&lt;br /&gt;
            pass&lt;br /&gt;
&lt;br /&gt;
# set some sane defaults&lt;br /&gt;
options = {&lt;br /&gt;
    &#039;use_ftp&#039;:&#039;0&#039;,&lt;br /&gt;
    &#039;ftp_server&#039;:&#039;&#039;,&lt;br /&gt;
    &#039;ftp_target_dir&#039;:&#039;&#039;,&lt;br /&gt;
    &#039;ftp_user&#039;:None,&lt;br /&gt;
    &#039;ftp_password&#039;:None,&lt;br /&gt;
    &#039;target_root&#039;: &#039;webroot&#039;,&lt;br /&gt;
    &#039;file_limit&#039;: &#039;10&#039;,&lt;br /&gt;
    &#039;verbose_log&#039;: &#039;1&#039;,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
# parse the config file, if it&#039;s there&lt;br /&gt;
print &amp;quot;Importing cfg\n&amp;quot;&lt;br /&gt;
try:&lt;br /&gt;
    config = open(&#039;rotate_demo.cfg&#039;, &#039;rt&#039;)&lt;br /&gt;
    for line_ in config:&lt;br /&gt;
        line = line_.strip()&lt;br /&gt;
        if len(line) == 0 or line.startswith(&#039;#&#039;): continue&lt;br /&gt;
        try:&lt;br /&gt;
            key, value = line.split(&#039;=&#039;)&lt;br /&gt;
            options[key.strip()] = value.strip()&lt;br /&gt;
        except ValueError, ex:&lt;br /&gt;
            print ex&lt;br /&gt;
except IOError:&lt;br /&gt;
    print &amp;quot;I/O Error on cfg read\n&amp;quot;&lt;br /&gt;
    pass&lt;br /&gt;
&lt;br /&gt;
if options[&#039;verbose_log&#039;] == &#039;1&#039;:&lt;br /&gt;
    sys.stdout = writer()&lt;br /&gt;
&lt;br /&gt;
# our first argument indicates the demo file which is ready to be moved&lt;br /&gt;
path = os.path.normpath(sys.argv[1].replace(&#039;&amp;quot;&#039;, &#039;&#039;))&lt;br /&gt;
&lt;br /&gt;
# handle local file shuffling (web server on same host as bf2 server, or on network share)&lt;br /&gt;
if options[&#039;use_ftp&#039;] == &#039;0&#039;:&lt;br /&gt;
    print &amp;quot;Using local file shuffle\n&amp;quot;&lt;br /&gt;
    # this is our target directory (i.e. the download dir)&lt;br /&gt;
    target_demo_dir = os.path.join(options[&#039;target_root&#039;], &#039;demos&#039;)&lt;br /&gt;
&lt;br /&gt;
    # create the directory structure if it doesn&#039;t exist&lt;br /&gt;
    ensure_exists(options[&#039;target_root&#039;])&lt;br /&gt;
    ensure_exists(os.path.join(options[&#039;target_root&#039;], &#039;demos&#039;))&lt;br /&gt;
&lt;br /&gt;
    if os.path.abspath(os.path.dirname(path)) != os.path.abspath(target_demo_dir):&lt;br /&gt;
        try:&lt;br /&gt;
            # NOTE: this requires atleast Python 2.3&lt;br /&gt;
            print &amp;quot;moving &#039;%s&#039; to &#039;%s&#039;&amp;quot; % (path, target_demo_dir)&lt;br /&gt;
            shutil.move(path, target_demo_dir)&lt;br /&gt;
        except IOError:&lt;br /&gt;
            sys.exit(1)&lt;br /&gt;
&lt;br /&gt;
    timestamped = []&lt;br /&gt;
&lt;br /&gt;
    # get a list of .bf2demo files in the target dir (including our own file)&lt;br /&gt;
    for pf in filter(lambda x: x.endswith(&#039;.bf2demo&#039;), os.listdir(target_demo_dir)):&lt;br /&gt;
        try:&lt;br /&gt;
            ppath = os.path.join(target_demo_dir, pf)&lt;br /&gt;
            os.chmod(ppath, 0644) # make web-readable&lt;br /&gt;
            timestamped.append((os.stat(ppath).st_mtime, ppath))&lt;br /&gt;
        except IOError:&lt;br /&gt;
            pass # don&#039;t let I/O errors stop us&lt;br /&gt;
&lt;br /&gt;
    # sort the timestamped file list according to modification time&lt;br /&gt;
    # NOTE: this sort is reversed so that older files are at the end of the list&lt;br /&gt;
    def compare_times(f1, f2): return cmp(f2[0], f1[0]) # note reverse sort order&lt;br /&gt;
    timestamped.sort(compare_times)&lt;br /&gt;
&lt;br /&gt;
    # delete the oldest files to meet the file limit&lt;br /&gt;
    file_limit = int(options[&#039;file_limit&#039;])&lt;br /&gt;
    for timestamp, deletium in timestamped[file_limit:]:&lt;br /&gt;
        try:&lt;br /&gt;
            os.remove(deletium)&lt;br /&gt;
        except IOError:&lt;br /&gt;
            pass # file in use?&lt;br /&gt;
&lt;br /&gt;
    # create the index file&lt;br /&gt;
    if 0: # dep: I guess this is superfluous&lt;br /&gt;
        idxf = open(os.path.join(options[&#039;target_root&#039;], &#039;index.lst&#039;), &#039;w&#039;)&lt;br /&gt;
        for timestamp, keptfile in timestamped[:file_limit]:&lt;br /&gt;
            fn = keptfile.split(os.sep)[-1]&lt;br /&gt;
            idxf.write(&#039;demos/%s\n&#039; % (fn))&lt;br /&gt;
        idxf.close()&lt;br /&gt;
&lt;br /&gt;
else: # use ftp&lt;br /&gt;
    print &amp;quot;Using FTP\n&amp;quot;&lt;br /&gt;
    try:&lt;br /&gt;
        import ftplib&lt;br /&gt;
        import re&lt;br /&gt;
&lt;br /&gt;
        path.replace(&#039;\\\\&#039;, &#039;\\&#039;)&lt;br /&gt;
&lt;br /&gt;
        path = os.path.normpath(path).replace(&#039;\\&#039;, &#039;/&#039;)&lt;br /&gt;
&lt;br /&gt;
        fn = path&lt;br /&gt;
        idx = fn.rfind(&#039;/&#039;)&lt;br /&gt;
        if idx != -1: fn = fn[idx+1:]&lt;br /&gt;
&lt;br /&gt;
        try:&lt;br /&gt;
            os.stat(path)&lt;br /&gt;
        except:&lt;br /&gt;
            # This shouldn&#039;t happen normally, only when testing from the cmd line&lt;br /&gt;
            print &amp;quot;ERROR- File does not exist: %s\nAborting\n&amp;quot; % (path)&lt;br /&gt;
            raise&lt;br /&gt;
       &lt;br /&gt;
        demof = open(path, &#039;rb&#039;)&lt;br /&gt;
&lt;br /&gt;
        # set up ftp connection&lt;br /&gt;
        print &amp;quot;Connecting to:\n\tHost: %s\n\tUser: %s\n\t Pwd: %s\n&amp;quot; % (options[&#039;ftp_server&#039;], options[&#039;ftp_user&#039;], options[&#039;ftp_password&#039;])&lt;br /&gt;
        try:&lt;br /&gt;
            ftp = ftplib.FTP(options[&#039;ftp_server&#039;], options[&#039;ftp_user&#039;], options[&#039;ftp_password&#039;])&lt;br /&gt;
        except:&lt;br /&gt;
            print &amp;quot;FTP ERROR: Connect failed!&amp;quot;&lt;br /&gt;
            raise&lt;br /&gt;
        print &amp;quot;Connected ... \n&amp;quot;&lt;br /&gt;
&lt;br /&gt;
        # change cwd&lt;br /&gt;
        print &amp;quot;Changing cwd to %s\n&amp;quot; % (options[&#039;ftp_target_dir&#039;])&lt;br /&gt;
        try:&lt;br /&gt;
            ftp.cwd(options[&#039;ftp_target_dir&#039;])&lt;br /&gt;
        except:&lt;br /&gt;
            print &amp;quot;FTP ERROR: failed to cwd =&amp;gt; %s&amp;quot; % (options[&#039;ftp_target_dir&#039;])&lt;br /&gt;
            raise&lt;br /&gt;
&lt;br /&gt;
        file_limit = int(options[&#039;file_limit&#039;])&lt;br /&gt;
&lt;br /&gt;
        print &amp;quot;Retrieving file listing from FTP ...\n&amp;quot;&lt;br /&gt;
        try:&lt;br /&gt;
            files = ftp.nlst()&lt;br /&gt;
        except Exception:&lt;br /&gt;
            files = []&lt;br /&gt;
&lt;br /&gt;
        files = filter(lambda x: x.endswith(&#039;.bf2demo&#039;), files)&lt;br /&gt;
        files.sort()&lt;br /&gt;
&lt;br /&gt;
        for file in files: print &amp;quot;\t&amp;quot; + file&lt;br /&gt;
&lt;br /&gt;
        # store the new file&lt;br /&gt;
        print &amp;quot;\nStoring new demo file: %s&amp;quot; % (fn)&lt;br /&gt;
        try:&lt;br /&gt;
            ftp.storbinary(&#039;STOR &#039;+fn, demof)&lt;br /&gt;
        except:&lt;br /&gt;
            print &amp;quot;FTP ERROR: Upload failed!&amp;quot;&lt;br /&gt;
               &lt;br /&gt;
        print &amp;quot;\tUpload complete!&amp;quot;&lt;br /&gt;
        demof.close()&lt;br /&gt;
&lt;br /&gt;
        # Remove the local file&lt;br /&gt;
        print &amp;quot;Removing local demo file %s&amp;quot; % (path)&lt;br /&gt;
        try:&lt;br /&gt;
            # delete local file&lt;br /&gt;
            os.unlink(path)&lt;br /&gt;
        except OSError:&lt;br /&gt;
            # couldn&#039;t unlink local file, what to do?&lt;br /&gt;
            print &amp;quot;ERROR- %s Could not be removed!&amp;quot; % (path)&lt;br /&gt;
            pass&lt;br /&gt;
&lt;br /&gt;
        # handle remote rotation&lt;br /&gt;
        print &amp;quot;\nHandling rotation and removing old FTP demos: file limit = %s&amp;quot; % (file_limit)&lt;br /&gt;
        while len(files) + 1 &amp;gt; file_limit:&lt;br /&gt;
            # dep: nb: this relies on the data formatting in the bf2demo filenames&lt;br /&gt;
            # if you have other&lt;br /&gt;
            print &#039;\tdeleting %s&#039; % (files[0])&lt;br /&gt;
            try:&lt;br /&gt;
                ftp.delete(files[0])&lt;br /&gt;
            except:&lt;br /&gt;
                print &amp;quot;FTP ERROR: Unable to delete %s&amp;quot; % (files[0])&lt;br /&gt;
                pass&lt;br /&gt;
            del files[0]&lt;br /&gt;
&lt;br /&gt;
        # bye bye&lt;br /&gt;
        ftp.quit()&lt;br /&gt;
        print &amp;quot;\nConnection closed&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    except Exception, detail:&lt;br /&gt;
        print &amp;quot;\n========================\nROTATE_DEMO ERROR!\n&amp;quot;&lt;br /&gt;
        import traceback&lt;br /&gt;
        log = open(&#039;rotate_demo_err.txt&#039;, &#039;w&#039;)&lt;br /&gt;
        ex = sys.exc_info()&lt;br /&gt;
        traceback.print_exception(ex[0], ex[1], ex[2], 16, log)&lt;br /&gt;
        print &amp;quot;%s\n%s\n%s\n%s\n%s&amp;quot; % (ex[0], ex[1], ex[2], 16, log)&lt;br /&gt;
        print &amp;quot;========================\n&amp;quot;&lt;br /&gt;
        log.write(&#039;\n&#039;)&lt;br /&gt;
        log.close()&lt;br /&gt;
        sys.exit(1)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Pireax</name></author>
	</entry>
	<entry>
		<id>https://bf2tech.uturista.pt/index.php?title=Scripts:RestartScript&amp;diff=130</id>
		<title>Scripts:RestartScript</title>
		<link rel="alternate" type="text/html" href="https://bf2tech.uturista.pt/index.php?title=Scripts:RestartScript&amp;diff=130"/>
		<updated>2018-06-22T15:36:50Z</updated>

		<summary type="html">&lt;p&gt;Pireax: Created page with &amp;quot;__TOC__ =  Server Restart Script (Linux Only)  =  The two scripts underneath are to be used in combination. These have as purpose to re-run the Battlefield 2 Dedicated Server...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
=  Server Restart Script (Linux Only)  =&lt;br /&gt;
&lt;br /&gt;
The two scripts underneath are to be used in combination. These have as purpose to re-run the Battlefield 2 Dedicated Server when it crashes or quits.&lt;br /&gt;
&lt;br /&gt;
==  startit.sh  ==&lt;br /&gt;
&lt;br /&gt;
This script initializes the servermonitor script in a screen. If you wish to run multiple server instances you need to change &#039;screenname&#039; to a different name.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE: Make sure to change /path/to/bf2 to your bf2 install dir!!!&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt; &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt; &amp;lt;/code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
#! /bin/sh&lt;br /&gt;
&lt;br /&gt;
screen -dmS screenname /path/to/bf2/servermonitor&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==  /path/to/bf2/servermonitor  ==&lt;br /&gt;
&lt;br /&gt;
This script constantly runs to check wheter the server still runs and restarts it when it doesnt run anymore.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE: Make sure to change /path/to/bf2 to your bf2 install dir!!!&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The only line needed to be changed will be &#039;exec=/path/to/bf2/start.sh&#039; (line 4)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt; &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt; &amp;lt;/code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
#! /bin/sh&lt;br /&gt;
&lt;br /&gt;
#full path to the start script for the process you want to monitor&lt;br /&gt;
exec=/path/to/bf2/start.sh&lt;br /&gt;
&lt;br /&gt;
#interval the script checks to see if the process is still running&lt;br /&gt;
interval=10&lt;br /&gt;
&lt;br /&gt;
while :&lt;br /&gt;
do&lt;br /&gt;
pid=$(ps ax | grep bf2 | grep bin | grep -v grep | awk &#039;{print $1}&#039;)&lt;br /&gt;
echo $pid&lt;br /&gt;
if [ -z &amp;quot;$pid&amp;quot; ]&lt;br /&gt;
then&lt;br /&gt;
date &amp;gt;&amp;gt; restartlog&lt;br /&gt;
echo $procName has stopped!!!! Starting $procName!!!! &amp;gt;&amp;gt; restartlog&lt;br /&gt;
echo &amp;quot; &amp;quot;&lt;br /&gt;
echo &amp;quot; &amp;quot;&lt;br /&gt;
&lt;br /&gt;
$exec&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
sleep $interval&lt;br /&gt;
done&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=  Made By  =&lt;br /&gt;
&lt;br /&gt;
These scripts where delivered to me by David Stevens and according to him they have been build by Rene Belloq.&lt;br /&gt;
&lt;br /&gt;
--Mortis 13:05, 11 Jul 2005 (MDT)&lt;br /&gt;
&lt;br /&gt;
=  Addendum  =&lt;br /&gt;
&lt;br /&gt;
Just copying the scripts above did not work for me on an actual Linux dedicated server with SuSE 10.2 running.&lt;br /&gt;
&lt;br /&gt;
You should now that i wanted to use them for our BF2 server running the AIX mod on it.&lt;br /&gt;
&lt;br /&gt;
First: I used as screenname &amp;quot;AIXMOD&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt; &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt; &amp;lt;/code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
#! /bin/sh&lt;br /&gt;
&lt;br /&gt;
screen -dmS AIXMOD /path/to/bf2/servermonitor&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
But &amp;quot;servermonitor&amp;quot; did not work, because the command for calling BF2 with the Mod parameter &amp;quot;exec=/path/to/bf2/start.sh +modPath mods/aix&amp;quot; is not known by the bash. Try to use a line calling it the way the shell can handle it instead:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt; &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt; &amp;lt;/code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
#! /bin/sh&lt;br /&gt;
 &lt;br /&gt;
#full path to the start script for the process you want to monitor&lt;br /&gt;
exec=&#039;./start.sh +modPath mods/aix +ignoreAsserts +fileMonitor 1&#039;&lt;br /&gt;
&lt;br /&gt;
#interval the script checks to see if the process is still running&lt;br /&gt;
interval=10&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
O.K., finally &amp;quot;servermonitor&amp;quot; started the BF2 server with the AIX mod. But then, the next &amp;quot;problem&amp;quot;: After the BF2 server crashed, the &amp;quot;servermonitor&amp;quot; did just a loop, always writing into the &amp;quot;restartlog&amp;quot; that the server is restarting. Again and again, but the server did not come up again. A short &amp;quot;ps x | grep bf2&amp;quot; showed why:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt; &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt; &amp;lt;/code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
11743 ?        S      0:00 sshd: bf2server@notty&lt;br /&gt;
11804 ?        S      0:00 sshd: bf2server@pts/1&lt;br /&gt;
11982 ?        Ss     0:00 SCREEN -dmS AIXMOD /home/bf2server/bf2/servermonitor&lt;br /&gt;
11983 pts/2    Ss+    0:00 /bin/sh /home/bf2server/bf2/servermonitor&lt;br /&gt;
11984 pts/2    Rl+    4:38 /home/bf2server/bf2/bin/amd-64/bf2 +modPath mods/aix&lt;br /&gt;
12328 pts/1    S+     0:00 grep bf2&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The script finds way too many pids, if you install your server files e.g. into a directory called &amp;quot;bf2&amp;quot; (as we did). So we checked the default grep command of the script and got 2 pids:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt; &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt; &amp;lt;/code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
bf2server@s15259444:~/bf2&amp;gt; ps x | grep bf2 | grep bin | grep -v grep | awk &#039;{print $1}&#039;&lt;br /&gt;
11983&lt;br /&gt;
11984&lt;br /&gt;
bf2server@s15259444:~/bf2&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
One of the &amp;quot;servermonitor&amp;quot; itself (pid:11983) and one of the BF2 server running (pid:11984). In order to get just the &amp;quot;interesting&amp;quot; pid we changed the grep command towards:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt; &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt; &amp;lt;/code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
bf2server@s15259444:~/bf2&amp;gt; ps x | grep bf2 | grep bin | grep -v grep | grep -v servermonitor | awk &#039;{print $1}&#039;&lt;br /&gt;
11984&lt;br /&gt;
bf2server@s15259444:~/bf2&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You see ^^, now we get only the pid of the &amp;quot;running&amp;quot; BF2 server, if the BF2 server crashes, that pid will be missing and the restart should work as intended. You should have got the principle how it works, change yours accordingly ;) Hope it helps.&lt;br /&gt;
&lt;br /&gt;
I forgot: You can also change the original grep command &amp;quot;grep bf2&amp;quot; towards a call for the part &amp;quot;amd-64&amp;quot; or &amp;quot;ia-32&amp;quot;, depending which you&#039;re using on your running AIX server:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt; &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt; &amp;lt;/code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
bf2server@s15259444:~&amp;gt; ps x | grep amd-64 | grep bin | grep -v grep | awk &#039;{print $1}&#039;&lt;br /&gt;
11984&lt;br /&gt;
bf2server@s15259444:~&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;/code&amp;gt; --BlackBears1 10:36, 16 January 2008 (MST)&lt;br /&gt;
&lt;br /&gt;
=  NARS (Not Another Restart Script)  =&lt;br /&gt;
&lt;br /&gt;
This Script has been made to be used under a Linux [http://www.rackaid.com/resources/tips/linux-screen.cfm Screen ]&lt;br /&gt;
&lt;br /&gt;
==  Script  ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
#&lt;br /&gt;
# Press Ctrl+C to stop the restarting&lt;br /&gt;
echo &amp;quot;##########################&amp;quot;&lt;br /&gt;
echo &amp;quot;# Bf2 Server Starting #&amp;quot;&lt;br /&gt;
echo &amp;quot;##########################&amp;quot;&lt;br /&gt;
echo To stop the restarting press Ctrl+C when the server is being restarted&lt;br /&gt;
echo&lt;br /&gt;
trap &#039;echo; echo $SRV Server Restarter has been STOPPED!; exit 1&#039; 2&lt;br /&gt;
C1=0&lt;br /&gt;
while true&lt;br /&gt;
do&lt;br /&gt;
C1=$((C1+=1))&lt;br /&gt;
cd /home/bf2srv/bf2&lt;br /&gt;
# Modify the line bellow to match your server execution command line&lt;br /&gt;
./start.sh&lt;br /&gt;
echo &amp;quot;Bf2 server restarted $C1 time(s)!&amp;quot;&lt;br /&gt;
sleep 10&lt;br /&gt;
done&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==  Usage  ==&lt;br /&gt;
&lt;br /&gt;
First, modify the path to the BF2 server directory on the script. Also you can add some extra variables to the ./start.sh script (like modPath or others). Then save the script as, for example, server_start.sh and store it on the bf2 directory.&lt;br /&gt;
&lt;br /&gt;
Do a:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;chmod +x server_start.sh &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then, open a new screen (just type screen, then enter), &#039;inside&#039; the screen, go to the BF2 server directory and type:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;./server_start.sh &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The server will start normally, then detach the screen by pressing &#039;CTRL + A&#039; and then &#039;D&#039;, the results must be something like:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;[detached] &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Yo can resume the screen and check the server console by doing a:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;screen -r PID &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
While PID is the process ID of the screen. If there are no other screen instanses running, you can resume this one using only screen -r&lt;br /&gt;
&lt;br /&gt;
If there is other screens running, the screen -r command will tell you the PIDs of those screens.&lt;br /&gt;
&lt;br /&gt;
===  Notes  ===&lt;br /&gt;
&lt;br /&gt;
This script will restart your server if it crashes or quit. Is very simple on the practice, dont be scared.&lt;br /&gt;
&lt;br /&gt;
--DarkPepe 03:32, 14 May 2006 (MDT)&lt;/div&gt;</summary>
		<author><name>Pireax</name></author>
	</entry>
	<entry>
		<id>https://bf2tech.uturista.pt/index.php?title=Scripts:Player_Position_Display&amp;diff=129</id>
		<title>Scripts:Player Position Display</title>
		<link rel="alternate" type="text/html" href="https://bf2tech.uturista.pt/index.php?title=Scripts:Player_Position_Display&amp;diff=129"/>
		<updated>2018-06-22T15:36:26Z</updated>

		<summary type="html">&lt;p&gt;Pireax: Created page with &amp;quot;__TOC__ == Purpose ==  When run on a testing server this script makes it easy to reposition items around when you&amp;#039;re doing server-side mods, as it saves you from opening the B...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
== Purpose ==&lt;br /&gt;
&lt;br /&gt;
When run on a testing server this script makes it easy to reposition items around when you&#039;re doing server-side mods, as it saves you from opening the BF2 Editor, or trying to get debug to work to get positions.&lt;br /&gt;
&lt;br /&gt;
This has only ever been used to find positions in a local dedicated server, and will probably cause all kinds of problems if run on a public server, as it probably won&#039;t handle map changes/more than 1 player.&lt;br /&gt;
&lt;br /&gt;
The positions have 1.0 subtracted from the y axis (vectors are right/up/forward format), as for the player object it is above ground level. Without this flags, vehicles and spawn points will all be above the ground. &lt;br /&gt;
&lt;br /&gt;
== Installation ==&lt;br /&gt;
&lt;br /&gt;
Requires Modmanager.&lt;br /&gt;
&lt;br /&gt;
Save the following to a file named mm_ppos.py in the [bf2server]/admin/modules/ folder, and add a line to enable it in modmanager.con (usually found in [bf2server]/mods/bf2/settings/).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;Player Position Display module.&lt;br /&gt;
&lt;br /&gt;
===== About =====&lt;br /&gt;
This ModManager script displays your current player object&#039;s position (less 1.0 in the z axis), and the direction you&#039;re facing.&lt;br /&gt;
 &lt;br /&gt;
Run it in a solo testing server to find map positions that may be used for server side modding.&lt;br /&gt;
&lt;br /&gt;
Running it on a public populated server will display the positions of all players, and make it difficult to find your own location&lt;br /&gt;
&lt;br /&gt;
===== History =====&lt;br /&gt;
&lt;br /&gt;
 v1.0 - 20080503:&lt;br /&gt;
 Initial public version&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
By polarity.&lt;br /&gt;
Available from bf2tech.org or flightschool.polar-lights.org.uk&lt;br /&gt;
You&#039;re free to use and modify this script&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
import bf2&lt;br /&gt;
import host&lt;br /&gt;
import mm_utils&lt;br /&gt;
from bf2.stats.constants import *&lt;br /&gt;
&lt;br /&gt;
# Set the version of your module here&lt;br /&gt;
__version__ = 1.0&lt;br /&gt;
&lt;br /&gt;
# Set the required module versions here&lt;br /&gt;
__required_modules__ = {&lt;br /&gt;
    &#039;modmanager&#039;: 1.0&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
# Does this module support reload ( are all its reference closed on shutdown? )&lt;br /&gt;
__supports_reload__ = True&lt;br /&gt;
&lt;br /&gt;
# Set the description of your module here&lt;br /&gt;
__description__ = &amp;quot;PlayerPositionDisplay v%s&amp;quot; % __version__&lt;br /&gt;
&lt;br /&gt;
updateTimer = None&lt;br /&gt;
 &lt;br /&gt;
class PlayerPos( object ):&lt;br /&gt;
&lt;br /&gt;
    def __init__( self, modManager ):&lt;br /&gt;
&lt;br /&gt;
        self.mm = modManager&lt;br /&gt;
        self.__state = 0&lt;br /&gt;
       &lt;br /&gt;
    def onPlayerSpawn(self, player, body ):&lt;br /&gt;
        if 1 != self.__state:&lt;br /&gt;
            return 0&lt;br /&gt;
        if (not player.isAIPlayer()):&lt;br /&gt;
            updateTimer = bf2.Timer( self.onUpdate, 1, 1 )&lt;br /&gt;
            updateTimer.setRecurring(2)&lt;br /&gt;
&lt;br /&gt;
    def StopTimer( self ):&lt;br /&gt;
        if 1 != self.__state:&lt;br /&gt;
            return 0&lt;br /&gt;
        if updateTimer:&lt;br /&gt;
            updateTimer.destroy()&lt;br /&gt;
            updateTimer = None&lt;br /&gt;
&lt;br /&gt;
    def onUpdate( self, data ):&lt;br /&gt;
        if 1 != self.__state:&lt;br /&gt;
            return 0&lt;br /&gt;
        #mm_utils.msg_server( &amp;quot;timer event called&amp;quot; )&lt;br /&gt;
        for player in bf2.playerManager.getPlayers():&lt;br /&gt;
            if not player.isAIPlayer():&lt;br /&gt;
                vehicle = player.getVehicle()&lt;br /&gt;
                try:&lt;br /&gt;
                    playerPos = vehicle.getPosition()&lt;br /&gt;
                    playerRot = vehicle.getRotation()&lt;br /&gt;
                    mm_utils.msg_player( player.index, &amp;quot;You are at: %.3f / %.3f / %.3f.  Looking %.1f degrees from North.&amp;quot; % (playerPos[0], playerPos[1] - 1, playerPos[2], playerRot[0] ) )&lt;br /&gt;
                    #mm_utils.msg_player( player.index, &amp;quot;--------------------------&amp;quot; )&lt;br /&gt;
                except:&lt;br /&gt;
                    mm_utils.msg_player( player.index, &amp;quot;failed to find soldier object&#039;s position&amp;quot; )&lt;br /&gt;
&lt;br /&gt;
    def init( self ):&lt;br /&gt;
        if 0 == self.__state:&lt;br /&gt;
            host.registerHandler( &#039;PlayerSpawn&#039;, self.onPlayerSpawn, 1 )&lt;br /&gt;
        # Update to the running state&lt;br /&gt;
        self.__state = 1&lt;br /&gt;
        updateTimer = None&lt;br /&gt;
&lt;br /&gt;
    def shutdown( self ):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Shutdown and stop processing.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
        # Unregister game handlers and do any other&lt;br /&gt;
        # other actions to ensure your module no longer affects&lt;br /&gt;
        # the game in anyway&lt;br /&gt;
       &lt;br /&gt;
        #stop the timer&lt;br /&gt;
        self.StopTimer()&lt;br /&gt;
        # Flag as shutdown as there is currently way to:&lt;br /&gt;
        # host.unregisterHandler&lt;br /&gt;
        self.__state = 2&lt;br /&gt;
&lt;br /&gt;
    def update( self ):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Process and update.&lt;br /&gt;
        Note: This is called VERY often processing in here should&lt;br /&gt;
        be kept to an absolute minimum.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        pass&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def mm_load( modManager ):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Creates and returns your object.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    return PlayerPos( modManager )&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Credits ==&lt;br /&gt;
&lt;br /&gt;
The writers of the other scripts found here on bf2tech.org. This uses some of them as a foundation.&lt;/div&gt;</summary>
		<author><name>Pireax</name></author>
	</entry>
	<entry>
		<id>https://bf2tech.uturista.pt/index.php?title=Scripts:UDP_Based_Advert_System&amp;diff=128</id>
		<title>Scripts:UDP Based Advert System</title>
		<link rel="alternate" type="text/html" href="https://bf2tech.uturista.pt/index.php?title=Scripts:UDP_Based_Advert_System&amp;diff=128"/>
		<updated>2018-06-22T15:36:09Z</updated>

		<summary type="html">&lt;p&gt;Pireax: Created page with &amp;quot;__TOC__ == Introduction ==  There are many ways to implement an advert system in BF2. A good way would probably be to use the RCON interface. But another one that might be wor...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
There are many ways to implement an advert system in BF2. A good way would probably be to use the RCON interface. But another one that might be worth playing around with, is a solution where you create a dedicated &#039;&#039;advert port&#039;&#039; on the server, and send messages to it at will, using a suitable client.&lt;br /&gt;
&lt;br /&gt;
== Server Code == &lt;br /&gt;
&lt;br /&gt;
The idea is to let the server listen on a port bound to the &#039;localhost&#039; interface, and read messages off that port, and post them to the players. The socket does of course need to be non-blocking, or it will interfere with the server. But I have no idea if the solution is to use a timer, like this code does. But this at least shows the consept:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
import socket&lt;br /&gt;
import host&lt;br /&gt;
import bf2&lt;br /&gt;
&lt;br /&gt;
port = 29600&lt;br /&gt;
addr = (&#039;localhost&#039;,port)&lt;br /&gt;
bufsize = 1024&lt;br /&gt;
&lt;br /&gt;
s = None&lt;br /&gt;
msgtimer = None&lt;br /&gt;
&lt;br /&gt;
def init():&lt;br /&gt;
   global s, msgtimer&lt;br /&gt;
   print &amp;quot;Initializing the &#039;advert client&#039; script.&amp;quot;&lt;br /&gt;
   s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)&lt;br /&gt;
   s.setblocking(0)&lt;br /&gt;
   s.bind(addr)&lt;br /&gt;
   msgtimer = bf2.Timer(read,1,1)&lt;br /&gt;
   msgtimer.setRecurring(1)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def read(data):&lt;br /&gt;
   if not s: return&lt;br /&gt;
   try:&lt;br /&gt;
      msg, client = s.recvfrom(bufsize)&lt;br /&gt;
   except:&lt;br /&gt;
      return False&lt;br /&gt;
   if msg:&lt;br /&gt;
      host.rcon_invoke(&amp;quot;game.sayAll \&amp;quot;&amp;quot; + str(msg) + &amp;quot;\&amp;quot;&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt; &lt;br /&gt;
&lt;br /&gt;
== Client Code ==&lt;br /&gt;
&lt;br /&gt;
The client can be as easy or complex as anyone wish. This is the simplest possible client:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/usr/bin/env python import socket  HOST = &#039;localhost&#039; PORT = 29600  print &amp;quot;Creating client socket.&amp;quot; s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) print &amp;quot;Sending data to server.&amp;quot; s.sendto(&amp;quot;Hi. I&#039;m an advert client sending data to the server.&amp;quot;, (HOST,PORT)) print &amp;quot;Closing socket.&amp;quot; s.close()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Pireax</name></author>
	</entry>
	<entry>
		<id>https://bf2tech.uturista.pt/index.php?title=Scripts:ReadingClanmembers&amp;diff=127</id>
		<title>Scripts:ReadingClanmembers</title>
		<link rel="alternate" type="text/html" href="https://bf2tech.uturista.pt/index.php?title=Scripts:ReadingClanmembers&amp;diff=127"/>
		<updated>2018-06-22T15:35:54Z</updated>

		<summary type="html">&lt;p&gt;Pireax: Created page with &amp;quot;For some scripts you need to add all your Clanmembers in an array.(for ex. Clan TK Protection) So I made a little Scriptpart which you can use to...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;For some scripts you need to add all your Clanmembers in an array.(for ex. [[Scripts:ClanTkProtection|Clan TK Protection]]) So I made a little Scriptpart which you can use to read all your Clanmembers from a file to an array.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
paste this code anywhere you would read the Members out of a File:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#######################################&lt;br /&gt;
#   Memberfilereader by Nexus2k       #&lt;br /&gt;
#                                     #&lt;br /&gt;
# Credits to Nexus2kSwiss and Net.BS| #&lt;br /&gt;
#       BlackSkorpions BF2 Clan       #&lt;br /&gt;
#            www.bs-dc.com            #&lt;br /&gt;
#######################################&lt;br /&gt;
#Open members.cfg in readmode&lt;br /&gt;
f=open(&#039;members.cfg&#039;,&#039;r&#039;)&lt;br /&gt;
#Each line become a Arrayitem in Array &amp;quot;clanmembers&amp;quot;&lt;br /&gt;
clanmembers=f.readlines()&lt;br /&gt;
#Close File&lt;br /&gt;
f.close()&lt;br /&gt;
#This deletes the &amp;quot;\n&amp;quot; after each member&lt;br /&gt;
clanmembers=[row.replace(&#039;\n&#039;,&#039;&#039;) for row in clanmembers]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
members.cfg:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Net.BS|Nexus2kSwiss&lt;br /&gt;
Net.BS|BlackSkull&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Just make a new Line after each Clanmember&lt;br /&gt;
&lt;br /&gt;
--Nexus2k 05:09, 8 Jul 2005 (MDT)&lt;/div&gt;</summary>
		<author><name>Pireax</name></author>
	</entry>
	<entry>
		<id>https://bf2tech.uturista.pt/index.php?title=Scripts:PostUrl&amp;diff=126</id>
		<title>Scripts:PostUrl</title>
		<link rel="alternate" type="text/html" href="https://bf2tech.uturista.pt/index.php?title=Scripts:PostUrl&amp;diff=126"/>
		<updated>2018-06-22T15:35:40Z</updated>

		<summary type="html">&lt;p&gt;Pireax: Created page with &amp;quot;&amp;#039;&amp;#039;&amp;#039;posturl&amp;#039;&amp;#039;&amp;#039; Usage of postdata(url, data):  &amp;lt;code&amp;gt;temp = postdata(&amp;#039;[http://www.yourdomain.com/postdata.php%27 http://www.yourdomain.com/postdata.php&amp;#039;], {&amp;#039;field1&amp;#039;: &amp;#039;field1data...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;posturl&#039;&#039;&#039; Usage of postdata(url, data):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;temp = postdata(&#039;[http://www.yourdomain.com/postdata.php%27 http://www.yourdomain.com/postdata.php&#039;], {&#039;field1&#039;: &#039;field1data&#039;, &#039;field2&#039;: &#039;field2data&#039;})&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
import string&lt;br /&gt;
import socket&lt;br /&gt;
import os&lt;br /&gt;
import time&lt;br /&gt;
import sys&lt;br /&gt;
import re&lt;br /&gt;
import urlparse&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    unicode&lt;br /&gt;
except NameError:&lt;br /&gt;
    def _is_unicode(x):&lt;br /&gt;
        return 0&lt;br /&gt;
else:&lt;br /&gt;
    def _is_unicode(x):&lt;br /&gt;
        return isinstance(x, unicode)&lt;br /&gt;
&lt;br /&gt;
def toBytes(url):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;toBytes(u&amp;quot;URL&amp;quot;) --&amp;gt; &#039;URL&#039;.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    # Most URL schemes require ASCII. If that changes, the conversion&lt;br /&gt;
    # can be relaxed&lt;br /&gt;
    if _is_unicode(url):&lt;br /&gt;
        try:&lt;br /&gt;
            url = url.encode(&amp;quot;ASCII&amp;quot;)&lt;br /&gt;
        except UnicodeError:&lt;br /&gt;
            raise UnicodeError(&amp;quot;URL &amp;quot; + repr(url) +&lt;br /&gt;
                               &amp;quot; contains non-ASCII characters&amp;quot;)&lt;br /&gt;
    return url&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def unquote(s):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;unquote(&#039;abc%20def&#039;) -&amp;gt; &#039;abc def&#039;.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    mychr = chr&lt;br /&gt;
    myatoi = int&lt;br /&gt;
    list = s.split(&#039;%&#039;)&lt;br /&gt;
    res = [list[0]]&lt;br /&gt;
    myappend = res.append&lt;br /&gt;
    del list[0]&lt;br /&gt;
    for item in list:&lt;br /&gt;
        if item[1:2]:&lt;br /&gt;
            try:&lt;br /&gt;
                myappend(mychr(myatoi(item[:2], 16))&lt;br /&gt;
                     + item[2:])&lt;br /&gt;
            except ValueError:&lt;br /&gt;
                myappend(&#039;%&#039; + item)&lt;br /&gt;
        else:&lt;br /&gt;
            myappend(&#039;%&#039; + item)&lt;br /&gt;
    return &amp;quot;&amp;quot;.join(res)&lt;br /&gt;
&lt;br /&gt;
def unquote_plus(s):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;unquote(&#039;%7e/abc+def&#039;) -&amp;gt; &#039;~/abc def&#039;&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    if &#039;+&#039; in s:&lt;br /&gt;
        # replace &#039;+&#039; with &#039; &#039;&lt;br /&gt;
        s = &#039; &#039;.join(s.split(&#039;+&#039;))&lt;br /&gt;
    return unquote(s)&lt;br /&gt;
&lt;br /&gt;
always_safe = (&#039;ABCDEFGHIJKLMNOPQRSTUVWXYZ&#039;&lt;br /&gt;
               &#039;abcdefghijklmnopqrstuvwxyz&#039;&lt;br /&gt;
               &#039;0123456789&#039; &#039;_.-&#039;)&lt;br /&gt;
&lt;br /&gt;
_fast_safe_test = always_safe + &#039;/&#039;&lt;br /&gt;
_fast_safe = None&lt;br /&gt;
&lt;br /&gt;
def _fast_quote(s):&lt;br /&gt;
    global _fast_safe&lt;br /&gt;
    if _fast_safe is None:&lt;br /&gt;
        _fast_safe = {}&lt;br /&gt;
        for c in _fast_safe_test:&lt;br /&gt;
            _fast_safe[c] = c&lt;br /&gt;
    res = list(s)&lt;br /&gt;
    for i in range(len(res)):&lt;br /&gt;
        c = res[i]&lt;br /&gt;
        if not c in _fast_safe:&lt;br /&gt;
            res[i] = &#039;%%%02X&#039; % ord(c)&lt;br /&gt;
    return &#039;&#039;.join(res)&lt;br /&gt;
&lt;br /&gt;
def quote(s, safe = &#039;/&#039;):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;quote(&#039;abc def&#039;) -&amp;gt; &#039;abc%20def&#039;&lt;br /&gt;
&lt;br /&gt;
    Each part of a URL, e.g. the path info, the query, etc., has a&lt;br /&gt;
    different set of reserved characters that must be quoted.&lt;br /&gt;
&lt;br /&gt;
    RFC 2396 Uniform Resource Identifiers (URI): Generic Syntax lists&lt;br /&gt;
    the following reserved characters.&lt;br /&gt;
&lt;br /&gt;
    reserved    = &amp;quot;;&amp;quot; | &amp;quot;/&amp;quot; | &amp;quot;?&amp;quot; | &amp;quot;:&amp;quot; | &amp;quot;@&amp;quot; | &amp;quot;&amp;amp;&amp;quot; | &amp;quot;=&amp;quot; | &amp;quot;+&amp;quot; |&lt;br /&gt;
                  &amp;quot;$&amp;quot; | &amp;quot;,&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    Each of these characters is reserved in some component of a URL,&lt;br /&gt;
    but not necessarily in all of them.&lt;br /&gt;
&lt;br /&gt;
    By default, the quote function is intended for quoting the path&lt;br /&gt;
    section of a URL.  Thus, it will not encode &#039;/&#039;.  This character&lt;br /&gt;
    is reserved, but in typical usage the quote function is being&lt;br /&gt;
    called on a path where the existing slash characters are used as&lt;br /&gt;
    reserved characters.&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    safe = always_safe + safe&lt;br /&gt;
    if _fast_safe_test == safe:&lt;br /&gt;
        return _fast_quote(s)&lt;br /&gt;
    res = list(s)&lt;br /&gt;
    for i in range(len(res)):&lt;br /&gt;
        c = res[i]&lt;br /&gt;
        if c not in safe:&lt;br /&gt;
            res[i] = &#039;%%%02X&#039; % ord(c)&lt;br /&gt;
    return &#039;&#039;.join(res)&lt;br /&gt;
&lt;br /&gt;
def quote_plus(s, safe = &#039;&#039;):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Quote the query fragment of a URL; replacing &#039; &#039; with &#039;+&#039;&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    if &#039; &#039; in s:&lt;br /&gt;
        l = s.split(&#039; &#039;)&lt;br /&gt;
        for i in range(len(l)):&lt;br /&gt;
            l[i] = quote(l[i], safe)&lt;br /&gt;
        return &#039;+&#039;.join(l)&lt;br /&gt;
    else:&lt;br /&gt;
        return quote(s, safe)&lt;br /&gt;
&lt;br /&gt;
def urlencode(query,doseq=0):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Encode a sequence of two-element tuples or dictionary into a URL query string.&lt;br /&gt;
&lt;br /&gt;
    If any values in the query arg are sequences and doseq is true, each&lt;br /&gt;
    sequence element is converted to a separate parameter.&lt;br /&gt;
&lt;br /&gt;
    If the query arg is a sequence of two-element tuples, the order of the&lt;br /&gt;
    parameters in the output will match the order of parameters in the&lt;br /&gt;
    input.&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    if hasattr(query,&amp;quot;items&amp;quot;):&lt;br /&gt;
        # mapping objects&lt;br /&gt;
        query = query.items()&lt;br /&gt;
    else:&lt;br /&gt;
        # it&#039;s a bother at times that strings and string-like objects are&lt;br /&gt;
        # sequences...&lt;br /&gt;
        try:&lt;br /&gt;
            # non-sequence items should not work with len()&lt;br /&gt;
            # non-empty strings will fail this&lt;br /&gt;
            if len(query) and not isinstance(query[0], tuple):&lt;br /&gt;
                raise TypeError&lt;br /&gt;
            # zero-length sequences of all types will get here and succeed,&lt;br /&gt;
            # but that&#039;s a minor nit - since the original implementation&lt;br /&gt;
            # allowed empty dicts that type of behavior probably should be&lt;br /&gt;
            # preserved for consistency&lt;br /&gt;
        except TypeError:&lt;br /&gt;
            ty,va,tb = sys.exc_info()&lt;br /&gt;
            raise TypeError, &amp;quot;not a valid non-string sequence or mapping object&amp;quot;, tb&lt;br /&gt;
&lt;br /&gt;
    l = []&lt;br /&gt;
    if not doseq:&lt;br /&gt;
        # preserve old behavior&lt;br /&gt;
        for k, v in query:&lt;br /&gt;
            k = quote_plus(str(k))&lt;br /&gt;
            v = quote_plus(str(v))&lt;br /&gt;
            l.append(k + &#039;=&#039; + v)&lt;br /&gt;
    else:&lt;br /&gt;
        for k, v in query:&lt;br /&gt;
            k = quote_plus(str(k))&lt;br /&gt;
            if isinstance(v, str):&lt;br /&gt;
                v = quote_plus(v)&lt;br /&gt;
                l.append(k + &#039;=&#039; + v)&lt;br /&gt;
            elif _is_unicode(v):&lt;br /&gt;
                # is there a reasonable way to convert to ASCII?&lt;br /&gt;
                # encode generates a string, but &amp;quot;replace&amp;quot; or &amp;quot;ignore&amp;quot;&lt;br /&gt;
                # lose information and &amp;quot;strict&amp;quot; can raise UnicodeError&lt;br /&gt;
                v = quote_plus(v.encode(&amp;quot;ASCII&amp;quot;,&amp;quot;replace&amp;quot;))&lt;br /&gt;
                l.append(k + &#039;=&#039; + v)&lt;br /&gt;
            else:&lt;br /&gt;
                try:&lt;br /&gt;
                    # is this a sufficient test for sequence-ness?&lt;br /&gt;
                    x = len(v)&lt;br /&gt;
                except TypeError:&lt;br /&gt;
                    # not a sequence&lt;br /&gt;
                    v = quote_plus(str(v))&lt;br /&gt;
                    l.append(k + &#039;=&#039; + v)&lt;br /&gt;
                else:&lt;br /&gt;
                    # loop over the sequence&lt;br /&gt;
                    for elt in v:&lt;br /&gt;
                        l.append(k + &#039;=&#039; + quote_plus(str(elt)))&lt;br /&gt;
    return &#039;&amp;amp;&#039;.join(l)&lt;br /&gt;
&lt;br /&gt;
def postdata(url, data):&lt;br /&gt;
    print &#039;in postdata function&#039;&lt;br /&gt;
        urldata = urlparse.urlparse(url)&lt;br /&gt;
        hostname = urldata[1]&lt;br /&gt;
        path = urldata[2]&lt;br /&gt;
    print hostname, path&lt;br /&gt;
        formdata = bf2.urllib.urlencode(data)&lt;br /&gt;
    print &amp;quot;formdata&amp;quot;, formdata&lt;br /&gt;
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)&lt;br /&gt;
        s.connect((hostname, 80))&lt;br /&gt;
        s.send(&amp;quot;POST %s HTTP/1.0\n&amp;quot; % path)&lt;br /&gt;
        s.send(&amp;quot;Host: %s\n&amp;quot; % hostname)&lt;br /&gt;
        s.send(&amp;quot;Connection: close\n&amp;quot;)&lt;br /&gt;
        s.send(&amp;quot;Content-type: application/x-www-form-urlencoded\n&amp;quot;)&lt;br /&gt;
        contentlength = &amp;quot;Content-length: %s\n\n&amp;quot; % len(formdata)&lt;br /&gt;
        s.send(contentlength)&lt;br /&gt;
        s.send(&amp;quot;%s&amp;quot; % formdata)&lt;br /&gt;
        splitter = re.compile(&#039;\r\n&#039;)&lt;br /&gt;
        while 1:&lt;br /&gt;
            buf = s.recv(1000)&lt;br /&gt;
            if not buf:&lt;br /&gt;
                break&lt;br /&gt;
            var = splitter.split(buf)&lt;br /&gt;
&lt;br /&gt;
        s.close()&lt;br /&gt;
        return &#039;\r\n&#039;.join(var)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Pireax</name></author>
	</entry>
	<entry>
		<id>https://bf2tech.uturista.pt/index.php?title=Scripts:EventsPy&amp;diff=125</id>
		<title>Scripts:EventsPy</title>
		<link rel="alternate" type="text/html" href="https://bf2tech.uturista.pt/index.php?title=Scripts:EventsPy&amp;diff=125"/>
		<updated>2018-06-22T15:35:25Z</updated>

		<summary type="html">&lt;p&gt;Pireax: Created page with &amp;quot;__TOC__ == What It Does  ==  * Prints connections, disconnections, and chat messages to the server console.  == Installation  ==  # Browse to &amp;lt;code&amp;gt;admin/standard_admin&amp;lt;/code&amp;gt;...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
== What It Does  ==&lt;br /&gt;
&lt;br /&gt;
* Prints connections, disconnections, and chat messages to the server console.&lt;br /&gt;
&lt;br /&gt;
== Installation  ==&lt;br /&gt;
&lt;br /&gt;
# Browse to &amp;lt;code&amp;gt;admin/standard_admin&amp;lt;/code&amp;gt; in your bf2 server directory&lt;br /&gt;
# Edit &amp;lt;code&amp;gt;__init__.py&amp;lt;/code&amp;gt; so it looks something like the code snippet below.&lt;br /&gt;
# Save the below code to &amp;lt;code&amp;gt;admin/standard_admin/events.py&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Run your server. If &amp;quot;&amp;lt;code&amp;gt;events.py loaded&amp;lt;/code&amp;gt;&amp;quot; comes up in your server console it should work from there.&lt;br /&gt;
&lt;br /&gt;
== Code  ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== __init__.py  ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
import autobalance&lt;br /&gt;
import tk_punish&lt;br /&gt;
import events&lt;br /&gt;
&lt;br /&gt;
autobalance.init()&lt;br /&gt;
tk_punish.init()&lt;br /&gt;
events.init()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== events.py  ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# script for viewing interesting events in the server console&lt;br /&gt;
# -- by dackz (http://dackz.net/)&lt;br /&gt;
&lt;br /&gt;
import bf2&lt;br /&gt;
import host&lt;br /&gt;
from bf2 import g_debug&lt;br /&gt;
&lt;br /&gt;
def init():&lt;br /&gt;
    if g_debug: print &#039;initialising events script&#039;&lt;br /&gt;
&lt;br /&gt;
    host.registerHandler(&#039;PlayerConnect&#039;, onPlayerConnect, 1)&lt;br /&gt;
    host.registerHandler(&#039;PlayerDisconnect&#039;, onPlayerDisconnect, 1)&lt;br /&gt;
    host.registerHandler(&#039;ChatMessage&#039;, onChatMessage, 1)&lt;br /&gt;
&lt;br /&gt;
    host.rcon_invoke(&#039;echo &amp;quot;events.py loaded&amp;quot;&#039;)&lt;br /&gt;
&lt;br /&gt;
def onPlayerConnect(player):&lt;br /&gt;
    host.rcon_invoke(&#039;echo &amp;quot;Connected: %s&amp;quot;&#039; % (player.getName()))&lt;br /&gt;
&lt;br /&gt;
def onPlayerDisconnect(player):&lt;br /&gt;
    host.rcon_invoke(&#039;echo &amp;quot;Disconnected: %s&amp;quot;&#039; % (player.getName()))&lt;br /&gt;
&lt;br /&gt;
def onChatMessage(player_id, text, channel, flags):&lt;br /&gt;
    player = bf2.playerManager.getPlayerByIndex(player_id)&lt;br /&gt;
&lt;br /&gt;
    host.rcon_invoke(&#039;echo &amp;quot;&amp;lt;%s&amp;gt;%s: %s&amp;quot;&#039; % (channel, player.getName(), text))&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Notes  ==&lt;br /&gt;
&lt;br /&gt;
The chat text might look a little weird as the script doesn&#039;t clean it up at all. You might see things like &amp;lt;code&amp;gt;HUD_TEXT_CHAT_TEAM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;*Â§DEADÂ§*&amp;lt;/code&amp;gt;, et cetera. Perhaps that will be fixed in the future.&lt;/div&gt;</summary>
		<author><name>Pireax</name></author>
	</entry>
	<entry>
		<id>https://bf2tech.uturista.pt/index.php?title=Scripts:EvalPy&amp;diff=124</id>
		<title>Scripts:EvalPy</title>
		<link rel="alternate" type="text/html" href="https://bf2tech.uturista.pt/index.php?title=Scripts:EvalPy&amp;diff=124"/>
		<updated>2018-06-22T15:35:11Z</updated>

		<summary type="html">&lt;p&gt;Pireax: Created page with &amp;quot;__TOC__ == What It Does  ==  * Allows you to test snippets of Python code while the server is running, without having to restart it to load changes from files.  == Installatio...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
== What It Does  ==&lt;br /&gt;
&lt;br /&gt;
* Allows you to test snippets of Python code while the server is running, without having to restart it to load changes from files.&lt;br /&gt;
&lt;br /&gt;
== Installation  ==&lt;br /&gt;
&lt;br /&gt;
# Browse to &amp;lt;code&amp;gt;admin/standard_admin&amp;lt;/code&amp;gt; in your bf2 server directory&lt;br /&gt;
# Edit &amp;lt;code&amp;gt;__init__.py&amp;lt;/code&amp;gt; so it looks something like the code snippet below.&lt;br /&gt;
# Save the below code to &amp;lt;code&amp;gt;admin/standard_admin/eval.py&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Make sure RCON is configured, then run your server. If &amp;quot;&amp;lt;code&amp;gt;eval.py loaded&amp;lt;/code&amp;gt;&amp;quot; comes up in your server console it should work from there.&lt;br /&gt;
&lt;br /&gt;
This doesn&#039;t work from the server console. You&#039;ll have to use an actual RCON client to use the command this script creates. The &amp;lt;code&amp;gt;remoteconsole.py&amp;lt;/code&amp;gt; script should work just fine.&lt;br /&gt;
&lt;br /&gt;
The command is &amp;quot;&amp;lt;code&amp;gt;eval [statement]&amp;lt;/code&amp;gt;&amp;quot;. An example would be something like the following:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;rcon&amp;gt; eval for i in dir(bf2.objectManager.getObjectsOfTemplate(&#039;c4_explosives&#039;)[0]): ctx.write(str(i) + &#039;\n&#039;)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Which then might return:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
__doc__&lt;br /&gt;
getChildren&lt;br /&gt;
getParent&lt;br /&gt;
getPosition&lt;br /&gt;
getRotation&lt;br /&gt;
getTemplateProperty&lt;br /&gt;
hasArmor&lt;br /&gt;
isControlPoint&lt;br /&gt;
isPlayerControlObject&lt;br /&gt;
isValid&lt;br /&gt;
setPosition&lt;br /&gt;
setRotation&lt;br /&gt;
templateName&lt;br /&gt;
token&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039; Be extra careful when using &amp;lt;code&amp;gt;ctx.write()&amp;lt;/code&amp;gt; over RCON. Though I have the script set to catch all exceptions, giving &amp;lt;code&amp;gt;ctx.write()&amp;lt;/code&amp;gt; a non-string will still cause an exception. Failure to take this into account can cause RCON to die completely. Using &amp;lt;code&amp;gt;ctx.write(str(variable))&amp;lt;/code&amp;gt; should keep you safe.&lt;br /&gt;
&lt;br /&gt;
== Code  ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== __init__.py  ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
import autobalance&lt;br /&gt;
import tk_punish&lt;br /&gt;
import eval&lt;br /&gt;
&lt;br /&gt;
autobalance.init()&lt;br /&gt;
tk_punish.init()&lt;br /&gt;
eval.init()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== eval.py  ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# script for eval()ing python code over rcon&lt;br /&gt;
# -- by dackz (http://dackz.net/)&lt;br /&gt;
&lt;br /&gt;
import sys&lt;br /&gt;
import new&lt;br /&gt;
import default&lt;br /&gt;
import bf2&lt;br /&gt;
import host&lt;br /&gt;
import game&lt;br /&gt;
import standard_admin&lt;br /&gt;
from bf2 import g_debug&lt;br /&gt;
&lt;br /&gt;
def write(self, text): self.write_original(str(text))&lt;br /&gt;
&lt;br /&gt;
def rcmd_eval(self, ctx, cmd):&lt;br /&gt;
    try:&lt;br /&gt;
        eval(compile(cmd, &#039;&amp;lt;string&amp;gt;&#039;, &#039;exec&#039;))&lt;br /&gt;
    except:&lt;br /&gt;
        ctx.write(str(sys.exc_info()[0]).split(&#039;.&#039;)[-1] + &#039;: &#039; + str(sys.exc_info()[1]) + &#039;\n&#039;)&lt;br /&gt;
&lt;br /&gt;
def init():&lt;br /&gt;
    if g_debug: print &#039;initialising eval script&#039;&lt;br /&gt;
&lt;br /&gt;
    default.CommandContext.write_original = default.CommandContext.write&lt;br /&gt;
    newMethod = new.instancemethod(write, None, default.CommandContext)&lt;br /&gt;
    default.CommandContext.write = newMethod&lt;br /&gt;
&lt;br /&gt;
    newMethod = new.instancemethod(rcmd_eval, default.server, default.AdminServer)&lt;br /&gt;
    default.AdminServer.rcmd_eval = newMethod&lt;br /&gt;
    default.server.rcon_cmds[&#039;eval&#039;] = default.AdminServer.rcmd_eval&lt;br /&gt;
&lt;br /&gt;
    host.rcon_invoke(&#039;echo &amp;quot;eval.py loaded&amp;quot;&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Pireax</name></author>
	</entry>
	<entry>
		<id>https://bf2tech.uturista.pt/index.php?title=Scripts:ConParser&amp;diff=123</id>
		<title>Scripts:ConParser</title>
		<link rel="alternate" type="text/html" href="https://bf2tech.uturista.pt/index.php?title=Scripts:ConParser&amp;diff=123"/>
		<updated>2018-06-22T15:34:56Z</updated>

		<summary type="html">&lt;p&gt;Pireax: Created page with &amp;quot;__TOC__ == Introduction  ==  This is a very simple parser for the BF2 Con files. You can use it to create BF-Style configs for your python scripts! I haven&amp;#039;t tried it in BF2 y...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
== Introduction  ==&lt;br /&gt;
&lt;br /&gt;
This is a very simple parser for the BF2 Con files. You can use it to create BF-Style configs for your python scripts! I haven&#039;t tried it in BF2 yet, but it should work fine :)&lt;br /&gt;
&lt;br /&gt;
Info: Variables and Expressions are not supported! This is just for reading and saving informations!&lt;br /&gt;
&lt;br /&gt;
== Features  ==&lt;br /&gt;
&lt;br /&gt;
* Reads Con files and returns it as a python list&lt;br /&gt;
* Writes Con files from a python list to file&lt;br /&gt;
&lt;br /&gt;
== Usage  ==&lt;br /&gt;
&lt;br /&gt;
Include the code and include it to your python script - very simple :)&lt;br /&gt;
&lt;br /&gt;
Read files:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;config = readCon(&#039;MyConfig.con&#039;) &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Write files:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;success = writeCon(config, &#039;MyConfig.con&#039;)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==  The Code  ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# ----------------------------------------------&lt;br /&gt;
# FIRE&#039;S SIMPLE CON PARSER&lt;br /&gt;
#&lt;br /&gt;
# CONTACT:&lt;br /&gt;
# fire_1@gmx.de&lt;br /&gt;
# www.flmod.com&lt;br /&gt;
#&lt;br /&gt;
# USAGE (READ):&lt;br /&gt;
# config = readCon(file)&lt;br /&gt;
# Returns a list: [{key1: [values1]}, {key2: [values2, values2]}, ...]&lt;br /&gt;
#&lt;br /&gt;
# USAGE (WRITE):&lt;br /&gt;
# success = writeCon(config, file)&lt;br /&gt;
# ----------------------------------------------&lt;br /&gt;
&lt;br /&gt;
# ----------------------------------------------&lt;br /&gt;
# Imports&lt;br /&gt;
# ----------------------------------------------&lt;br /&gt;
import string&lt;br /&gt;
from bf2 import g_debug&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def readCon(conFile):&lt;br /&gt;
    config = []&lt;br /&gt;
    rem = False&lt;br /&gt;
   &lt;br /&gt;
    # ----------------------------------------------&lt;br /&gt;
    # Open the file&lt;br /&gt;
    # ----------------------------------------------&lt;br /&gt;
    if g_debug:&lt;br /&gt;
        print &#039;Reading CON file...&#039;&lt;br /&gt;
   &lt;br /&gt;
    try:&lt;br /&gt;
        f = file(conFile, &#039;r&#039;)&lt;br /&gt;
        lines = f.readlines()&lt;br /&gt;
        f.close()&lt;br /&gt;
    except IOError: # Damn..&lt;br /&gt;
        if g_debug:&lt;br /&gt;
            print &#039;Error while reading CON file!!&#039;&lt;br /&gt;
       &lt;br /&gt;
        return config&lt;br /&gt;
&lt;br /&gt;
   &lt;br /&gt;
    for line in lines:&lt;br /&gt;
        # ----------------------------------------------&lt;br /&gt;
        # Replace tabs etc.&lt;br /&gt;
        # ----------------------------------------------&lt;br /&gt;
        line = string.replace(line, &#039;\t&#039;, &#039;\x20&#039;)&lt;br /&gt;
        line = string.strip(line, &#039;\x20\n&#039;)&lt;br /&gt;
&lt;br /&gt;
        # ----------------------------------------------&lt;br /&gt;
        # Remove comments&lt;br /&gt;
        # ----------------------------------------------&lt;br /&gt;
        if string.strip(string.lower(line[:4])) == &#039;rem&#039;:&lt;br /&gt;
            continue&lt;br /&gt;
        elif string.strip(string.lower(line[:9])) == &#039;beginrem&#039;:&lt;br /&gt;
            rem = True&lt;br /&gt;
            continue&lt;br /&gt;
        elif string.strip(string.lower(line[:7])) == &#039;endrem&#039;:&lt;br /&gt;
            rem = False&lt;br /&gt;
            continue&lt;br /&gt;
        else:&lt;br /&gt;
            if rem:&lt;br /&gt;
                continue&lt;br /&gt;
&lt;br /&gt;
        # ----------------------------------------------&lt;br /&gt;
        # Find the end of the key&lt;br /&gt;
        # ----------------------------------------------&lt;br /&gt;
        pos = string.find(line, &#039;\x20&#039;)&lt;br /&gt;
        if pos &amp;lt; 0: # Not found :(&lt;br /&gt;
            continue&lt;br /&gt;
&lt;br /&gt;
        # ----------------------------------------------&lt;br /&gt;
        # Get the key&lt;br /&gt;
        # ----------------------------------------------&lt;br /&gt;
        key = line[:pos]&lt;br /&gt;
&lt;br /&gt;
        # ----------------------------------------------&lt;br /&gt;
        # Get the values&lt;br /&gt;
        # ----------------------------------------------&lt;br /&gt;
        values = string.split(line[pos + 1:], &#039;\x20&#039;)&lt;br /&gt;
        for value in values:&lt;br /&gt;
            value = string.strip(value, &#039;\x20&#039;)&lt;br /&gt;
&lt;br /&gt;
        config.append({key: values})&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    # ----------------------------------------------&lt;br /&gt;
    # Return the list&lt;br /&gt;
    # ----------------------------------------------&lt;br /&gt;
    return config&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# --------------------------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def writeCon(config, conFile):&lt;br /&gt;
    # ----------------------------------------------&lt;br /&gt;
    # Open the file&lt;br /&gt;
    # ----------------------------------------------&lt;br /&gt;
    if g_debug:&lt;br /&gt;
        print &#039;Writing CON file...&#039;&lt;br /&gt;
   &lt;br /&gt;
    try:&lt;br /&gt;
        f = file(conFile, &#039;w+&#039;)&lt;br /&gt;
        pass&lt;br /&gt;
    except IOError: # Damn..&lt;br /&gt;
        return False&lt;br /&gt;
   &lt;br /&gt;
    data = &#039;rem *** Created with FiRe\&#039;s CON parser ***\n\n&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    # ----------------------------------------------&lt;br /&gt;
    # Create the Con file&lt;br /&gt;
    # ----------------------------------------------&lt;br /&gt;
    for conf in config:&lt;br /&gt;
        # ----------------------------------------------&lt;br /&gt;
        # Add the key&lt;br /&gt;
        # ----------------------------------------------&lt;br /&gt;
        data += conf.items()[0][0]&lt;br /&gt;
       &lt;br /&gt;
        # ----------------------------------------------&lt;br /&gt;
        # Add the values&lt;br /&gt;
        # ----------------------------------------------&lt;br /&gt;
        for key in conf.items()[0][1]:&lt;br /&gt;
            data += &#039; &#039; + key&lt;br /&gt;
        data += &#039;\n&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    # ----------------------------------------------&lt;br /&gt;
    # Write the config to file&lt;br /&gt;
    # ----------------------------------------------&lt;br /&gt;
    try:&lt;br /&gt;
        f.write(data)&lt;br /&gt;
        f.close()&lt;br /&gt;
    except IOError:&lt;br /&gt;
        if g_debug:&lt;br /&gt;
            print &#039;Error while writing CON file!!&#039;&lt;br /&gt;
        return False&lt;br /&gt;
    else:&lt;br /&gt;
        return True&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Pireax</name></author>
	</entry>
	<entry>
		<id>https://bf2tech.uturista.pt/index.php?title=Scripts:Aircraft_Only&amp;diff=122</id>
		<title>Scripts:Aircraft Only</title>
		<link rel="alternate" type="text/html" href="https://bf2tech.uturista.pt/index.php?title=Scripts:Aircraft_Only&amp;diff=122"/>
		<updated>2018-06-22T15:34:39Z</updated>

		<summary type="html">&lt;p&gt;Pireax: Created page with &amp;quot;__TOC__  == Purpose ==  Makes playing outside of an aircraft rather pointless, as you only get 25 seconds before you start to take damage. This was needed as an admin script o...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== Purpose ==&lt;br /&gt;
&lt;br /&gt;
Makes playing outside of an aircraft rather pointless, as you only get 25 seconds before you start to take damage. This was needed as an admin script on the Coop Flight School server, as there are limited slots, and players on the ground treating it like a normal server were using slots intended for learner pilots.&lt;br /&gt;
&lt;br /&gt;
Could be adapted for use with other vehicles, if for example you wanted to have tank battles or DPV races.&lt;br /&gt;
&lt;br /&gt;
== Installation ==&lt;br /&gt;
&lt;br /&gt;
Requires Modmanager.&lt;br /&gt;
&lt;br /&gt;
Save the following to a file named mm_aironly.py in the [bf2server]/admin/modules/ folder, and add a line to enable it in modmanager.con (usually found in [bf2server]/mods/bf2/settings/).&lt;br /&gt;
&lt;br /&gt;
== The Code ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;Aircraft Only module.&lt;br /&gt;
&lt;br /&gt;
===== About =====&lt;br /&gt;
This ModManager script prevents players from playing as infantry or in ground vehicles,&lt;br /&gt;
by causing damage to players who exit the vehicles they&#039;re spawned in.  Players are given&lt;br /&gt;
a warning on exiting, then 25 seconds later they start to receive damage on a 5 second&lt;br /&gt;
interval, with further warnings.  If they get back into the vehicle then the damage stops.&lt;br /&gt;
If they try to get round it by standing near a resupply/crate/medic then the damage rate&lt;br /&gt;
will increase to counter the healing.&lt;br /&gt;
&lt;br /&gt;
===== Config =====&lt;br /&gt;
 Enter the allowed classes in the RequiredTypes list below&lt;br /&gt;
&lt;br /&gt;
===== History =====&lt;br /&gt;
&lt;br /&gt;
 v2.1 - 20080507:&lt;br /&gt;
 v2 bugfix&lt;br /&gt;
&lt;br /&gt;
 timers are per player to fix bug from sharing that would punish at wrong time/crash server (no OOP experience before this script)&lt;br /&gt;
&lt;br /&gt;
 vehicle parent added to allow gunners/copilots/passengers (still gives warning when switching seats though)&lt;br /&gt;
&lt;br /&gt;
 damage switched from 10/2s to 25/5s and delay upped to 20s from 25s&lt;br /&gt;
&lt;br /&gt;
 everything reset correctly at round end&lt;br /&gt;
&lt;br /&gt;
===== Credit =====&lt;br /&gt;
&lt;br /&gt;
By polarity, loosely based on vehicle class limit&lt;br /&gt;
module by graag42, and other scripts from bf2tech.org&lt;br /&gt;
&lt;br /&gt;
Available from bf2tech.org and flightschool.polar-lights.org.uk&lt;br /&gt;
You&#039;re free to use and modify this script&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
import bf2&lt;br /&gt;
import host&lt;br /&gt;
import mm_utils&lt;br /&gt;
from bf2.stats.constants import *&lt;br /&gt;
&lt;br /&gt;
# Set the version of your module here&lt;br /&gt;
__version__ = 2.1&lt;br /&gt;
&lt;br /&gt;
# Set the required module versions here&lt;br /&gt;
__required_modules__ = {&lt;br /&gt;
    &#039;modmanager&#039;: 1.0&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
# Does this module support reload ( are all its reference closed on shutdown? )&lt;br /&gt;
__supports_reload__ = True&lt;br /&gt;
&lt;br /&gt;
# Set the description of your module here&lt;br /&gt;
__description__ = &amp;quot;VehicleClassOnly v%s&amp;quot; % __version__&lt;br /&gt;
&lt;br /&gt;
#Required types are safe to be in&lt;br /&gt;
RequiredTypes = [VEHICLE_TYPE_HELICOPTER, VEHICLE_TYPE_AVIATOR]       &lt;br /&gt;
&lt;br /&gt;
class NoWalk( object ):&lt;br /&gt;
&lt;br /&gt;
    def __init__( self, modManager ):&lt;br /&gt;
&lt;br /&gt;
        self.mm = modManager&lt;br /&gt;
        self.__state = 0&lt;br /&gt;
       &lt;br /&gt;
    def onExitVehicle( self, player, vehicle):&lt;br /&gt;
        if self.__state == 1:&lt;br /&gt;
            if ( (not player.isAIPlayer()) &amp;amp; player.isAlive()): #exited vehicle intentionally&lt;br /&gt;
                if not player.updateTimer:&lt;br /&gt;
                    self.StartTimer( player )&lt;br /&gt;
               &lt;br /&gt;
    def onEnterVehicle( self, player, vehicle, freeSoldier):&lt;br /&gt;
        if self.__state == 1:&lt;br /&gt;
            if (not player.isAIPlayer()):&lt;br /&gt;
                vehicleType = getVehicleType(vehicle.templateName)&lt;br /&gt;
                try:&lt;br /&gt;
                    parentVehicle = vehicle.getParent()&lt;br /&gt;
                    parentType = getVehicleType(parentVehicle.templateName)&lt;br /&gt;
                except:&lt;br /&gt;
                    parentType = 12&lt;br /&gt;
                if ( vehicleType in RequiredTypes ) | ( parentType in RequiredTypes ):&lt;br /&gt;
                    if player.updateTimer:&lt;br /&gt;
                        self.ResetPlayer( player )&lt;br /&gt;
                else:&lt;br /&gt;
                    if not player.updateTimer:&lt;br /&gt;
                        self.StartTimer( player )&lt;br /&gt;
&lt;br /&gt;
    def onPlayerConnect(self, player ):&lt;br /&gt;
        if self.__state == 1:&lt;br /&gt;
            if (not player.isAIPlayer()):&lt;br /&gt;
                player.updateTimer = None&lt;br /&gt;
                self.ResetPlayer( player )&lt;br /&gt;
&lt;br /&gt;
    def onPlayerSpawn(self, player, body):&lt;br /&gt;
        if self.__state == 1:&lt;br /&gt;
            if (not player.isAIPlayer()):&lt;br /&gt;
                self.ResetPlayer( player )&lt;br /&gt;
                bf2.Timer(self.PostSpawnTest, 1, 1, player )&lt;br /&gt;
&lt;br /&gt;
    def PostSpawnTest(self, player):&lt;br /&gt;
        if 1 != self.__state:&lt;br /&gt;
            return 0&lt;br /&gt;
        if (not player.isAIPlayer()):&lt;br /&gt;
            vehicle = player.getVehicle()&lt;br /&gt;
            vehicleType = getVehicleType(vehicle.templateName)&lt;br /&gt;
            try:&lt;br /&gt;
                parentVehicle = vehicle.getParent()&lt;br /&gt;
                parentType = getVehicleType(parentVehicle.templateName)&lt;br /&gt;
            except:&lt;br /&gt;
                parentType = 12&lt;br /&gt;
            if ( vehicleType in RequiredTypes ) | ( parentType in RequiredTypes ):           &lt;br /&gt;
                if player.updateTimer:&lt;br /&gt;
                    self.ResetPlayer( player )&lt;br /&gt;
            else:&lt;br /&gt;
                if not player.updateTimer:&lt;br /&gt;
                    self.StartTimer( player )&lt;br /&gt;
&lt;br /&gt;
    def onPlayerDeath(self, player, body):&lt;br /&gt;
        if self.__state == 1:&lt;br /&gt;
            if (not player.isAIPlayer()):&lt;br /&gt;
                self.ResetPlayer( player )&lt;br /&gt;
&lt;br /&gt;
    def StartTimer( self, player ):&lt;br /&gt;
        if 1 != self.__state:&lt;br /&gt;
            return 0&lt;br /&gt;
        mm_utils.msg_player( player.index, &amp;quot;Fighting on the ground is not permitted in this server.&amp;quot; )&lt;br /&gt;
        mm_utils.msg_player( player.index, &amp;quot;You must enter an aircraft within 25 seconds to avoid punishment.&amp;quot; )&lt;br /&gt;
        player.updateTimer = bf2.Timer(self.onUpdate, 25, 1, player )&lt;br /&gt;
        player.updateTimer.setRecurring(5)&lt;br /&gt;
&lt;br /&gt;
    def StopTimer( self, player ):&lt;br /&gt;
        if 1 != self.__state:&lt;br /&gt;
            return 0&lt;br /&gt;
        if player.updateTimer:&lt;br /&gt;
            player.updateTimer.destroy()&lt;br /&gt;
            player.updateTimer = None&lt;br /&gt;
       &lt;br /&gt;
&lt;br /&gt;
    def onUpdate( self, player ):&lt;br /&gt;
        if 1 != self.__state:&lt;br /&gt;
            return 0&lt;br /&gt;
        body = player.getDefaultVehicle()&lt;br /&gt;
        damage = body.getDamage()&lt;br /&gt;
        if damage &amp;gt; 0:    #If you&#039;re not dead...&lt;br /&gt;
            if ((player.lastDamage &amp;lt;= damage) &amp;amp; (player.lastDamage != None) &amp;amp; (player.damageRate &amp;lt; 3000)):  #if you&#039;ve been getting healed&lt;br /&gt;
                player.damageRate += 25&lt;br /&gt;
                mm_utils.msg_player( player.index, &amp;quot;You can&#039;t avoid punishment by healing.  Increasing damage rate.&amp;quot; )&lt;br /&gt;
            elif (player.lastDamage &amp;gt;= damage):&lt;br /&gt;
                player.damageRate = 25&lt;br /&gt;
                mm_utils.msg_player( player.index, &amp;quot;Pilots must use aircraft to avoid punishment for being AWOL.&amp;quot; )&lt;br /&gt;
            else:&lt;br /&gt;
                mm_utils.msg_player( player.index, &amp;quot;Pilots must use aircraft to avoid punishment for being AWOL.&amp;quot; )&lt;br /&gt;
            player.lastDamage = damage&lt;br /&gt;
            body.setDamage(damage-player.damageRate)&lt;br /&gt;
            if body.getDamage() &amp;lt; 0:&lt;br /&gt;
                mm_utils.msg_server( &amp;quot;Pilot %s was killed for going AWOL.&amp;quot; % player.getName() )&lt;br /&gt;
&lt;br /&gt;
    def ResetPlayer( self, player ):&lt;br /&gt;
        player.damageRate = 25&lt;br /&gt;
        player.lastDamage = None&lt;br /&gt;
        self.StopTimer( player )&lt;br /&gt;
&lt;br /&gt;
    def ResetAll( self ):&lt;br /&gt;
        for player in bf2.playerManager.getPlayers():&lt;br /&gt;
            if (not player.isAIPlayer()):&lt;br /&gt;
                self.ResetPlayer( player )&lt;br /&gt;
               &lt;br /&gt;
    def onGameStatusChanged( self, status ):&lt;br /&gt;
    # Enables the idle check timer&lt;br /&gt;
    # Import variables, and update the game status:&lt;br /&gt;
        global gamestatus&lt;br /&gt;
        gamestatus = status&lt;br /&gt;
        if gamestatus == bf2.GameStatus.EndGame:&lt;br /&gt;
            self.ResetAll()&lt;br /&gt;
&lt;br /&gt;
    def init( self ):&lt;br /&gt;
        if 0 == self.__state:&lt;br /&gt;
            host.registerHandler( &#039;ExitVehicle&#039;, self.onExitVehicle, 1 )&lt;br /&gt;
            host.registerHandler( &#039;EnterVehicle&#039;, self.onEnterVehicle, 1 )&lt;br /&gt;
            host.registerHandler( &#039;PlayerConnect&#039;, self.onPlayerConnect, 1 )&lt;br /&gt;
            host.registerHandler( &#039;PlayerSpawn&#039;, self.onPlayerSpawn, 1 )&lt;br /&gt;
            host.registerHandler( &#039;PlayerDeath&#039;, self.onPlayerDeath, 1 )&lt;br /&gt;
            host.registerGameStatusHandler(self.onGameStatusChanged)&lt;br /&gt;
           &lt;br /&gt;
           &lt;br /&gt;
        # Update to the running state&lt;br /&gt;
        self.__state = 1&lt;br /&gt;
&lt;br /&gt;
    def shutdown( self ):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Shutdown and stop processing.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
        # Unregister game handlers and do any other&lt;br /&gt;
        # other actions to ensure your module no longer affects&lt;br /&gt;
        # the game in anyway&lt;br /&gt;
&lt;br /&gt;
        self.ResetAll()&lt;br /&gt;
&lt;br /&gt;
        # Flag as shutdown as there is currently way to:&lt;br /&gt;
        # host.unregisterHandler&lt;br /&gt;
        self.__state = 2&lt;br /&gt;
&lt;br /&gt;
    def update( self ):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Process and update.&lt;br /&gt;
        Note: This is called VERY often processing in here should&lt;br /&gt;
        be kept to an absolute minimum.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        pass&lt;br /&gt;
&lt;br /&gt;
def mm_load( modManager ):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Creates and returns your object.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    return NoWalk( modManager )&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Credits ==&lt;br /&gt;
&lt;br /&gt;
Mainly to Graag, as his class limit script was my main reference for this, my first attempt at BF2 python coding.&lt;/div&gt;</summary>
		<author><name>Pireax</name></author>
	</entry>
	<entry>
		<id>https://bf2tech.uturista.pt/index.php?title=Scripts:Vehicle_Class_Limit&amp;diff=121</id>
		<title>Scripts:Vehicle Class Limit</title>
		<link rel="alternate" type="text/html" href="https://bf2tech.uturista.pt/index.php?title=Scripts:Vehicle_Class_Limit&amp;diff=121"/>
		<updated>2018-06-22T15:34:25Z</updated>

		<summary type="html">&lt;p&gt;Pireax: Created page with &amp;quot;__TOC__ == Introduction  ==  This ModManager script prevents use of certain vehicle classes.  Whenever a player enters one of the forbidden vehicles a 10 second timer is start...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
== Introduction  ==&lt;br /&gt;
&lt;br /&gt;
This ModManager script prevents use of certain vehicle classes.&lt;br /&gt;
&lt;br /&gt;
Whenever a player enters one of the forbidden vehicles a 10 second timer is started if it&#039;s not already running.&lt;br /&gt;
&lt;br /&gt;
When the timer is activated it checks all the players and tries to punish the trespassers. As it&#039;s almost impossible to kill a player serverside (the player could be standing near a supply drop, health pack, heli landing pack etc.) the script decreases the health of player and the occupied vehicle, hoping for a fast explosion.&lt;br /&gt;
&lt;br /&gt;
The timer is deactivated if no players were in the forbidden vehicles.&lt;br /&gt;
&lt;br /&gt;
== Prerequisites  ==&lt;br /&gt;
&lt;br /&gt;
[[ModManager|ModManager]] or [http://www.bf2cc.com/ BF2CC]&lt;br /&gt;
&lt;br /&gt;
== Install  ==&lt;br /&gt;
&lt;br /&gt;
* unzip the file (or copy and paste into &#039;&#039;mm_climit.py&#039;&#039;) to &#039;&#039;admin/modules&#039;&#039; in your Battlefield 2 server install.&lt;br /&gt;
* if necessary, edit the file and change the forbidden classes (by default the forbidden classes are Armor, Helicopter and Aircraft)&lt;br /&gt;
* change your &#039;&#039;modmanager.con&#039;&#039; and include the following line:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&#039;&#039;modmanager.loadModule &amp;quot;mm_climit&amp;quot;&#039;&#039;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Code  ==&lt;br /&gt;
&lt;br /&gt;
=== Download  ===&lt;br /&gt;
&lt;br /&gt;
The source is included below and the current version is also available [http://www.slo-gamers.com/upload/mm_climit.zip here].&lt;br /&gt;
&lt;br /&gt;
=== Readable  ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# vim: ts=4 sw=4 noexpandtab&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;Vehicle class limit module.&lt;br /&gt;
&lt;br /&gt;
===== About =====&lt;br /&gt;
 This ModManager script prevents use of certain vehicle classes.&lt;br /&gt;
 Whenever a player enters one of the forbidden vehicles a 10 second timer is started if&lt;br /&gt;
 it&#039;s not already running.&lt;br /&gt;
 When the timer is activated it checks all the players and tries to punish the trespassers.&lt;br /&gt;
 As it&#039;s almost impossible to kill a player serverside (the player could be standing near&lt;br /&gt;
 a supply drop, health pack, heli landing pack etc.) the script decreases the health of&lt;br /&gt;
 player and the occupied vehicle, hoping for a fast explosion. ;)&lt;br /&gt;
 The timer is deactivated if no players were in the forbidden vehicles.&lt;br /&gt;
&lt;br /&gt;
===== Config =====&lt;br /&gt;
 Enter the forbidden classes in the ForbiddenTypes list below&lt;br /&gt;
&lt;br /&gt;
===== History =====&lt;br /&gt;
&lt;br /&gt;
 v1.0 - 20060119:&lt;br /&gt;
 Initial public version&lt;br /&gt;
 v0.9 - 20051224:&lt;br /&gt;
 Internal release&lt;br /&gt;
&lt;br /&gt;
Author: graag42atgmaildotcom&lt;br /&gt;
You&#039;re free to use and modify this script&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
import bf2&lt;br /&gt;
import host&lt;br /&gt;
import mm_utils&lt;br /&gt;
from bf2.stats.constants import *&lt;br /&gt;
&lt;br /&gt;
# Set the version of your module here&lt;br /&gt;
__version__ = 1.0&lt;br /&gt;
&lt;br /&gt;
# Set the required module versions here&lt;br /&gt;
__required_modules__ = {&lt;br /&gt;
    &#039;modmanager&#039;: 1.0&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
# Does this module support reload ( are all its reference closed on shutdown? )&lt;br /&gt;
__supports_reload__ = True&lt;br /&gt;
&lt;br /&gt;
# Set the description of your module here&lt;br /&gt;
__description__ = &amp;quot;VehicleClassLimit v%s&amp;quot; % __version__&lt;br /&gt;
&lt;br /&gt;
#comma separated list of forbidden classes ( defined in bf2.stats.constants )&lt;br /&gt;
ForbiddenTypes = [VEHICLE_TYPE_ARMOR, VEHICLE_TYPE_AVIATOR, VEHICLE_TYPE_HELICOPTER]       &lt;br /&gt;
&lt;br /&gt;
updateTimer = None&lt;br /&gt;
 &lt;br /&gt;
class NoFly( object ):&lt;br /&gt;
&lt;br /&gt;
    def __init__( self, modManager ):&lt;br /&gt;
        # ModManager reference&lt;br /&gt;
        self.mm = modManager&lt;br /&gt;
       &lt;br /&gt;
        # Internal shutdown state&lt;br /&gt;
        self.__state = 0&lt;br /&gt;
       &lt;br /&gt;
        # Add any static initialisation here.&lt;br /&gt;
        # Note: Handler registration should not be done here&lt;br /&gt;
        # but instead in the init() method&lt;br /&gt;
&lt;br /&gt;
    def onEnterVehicle( self, player, vehicle, freeSoldier):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Player entered a vehicle - check if the class is allowed and start the timer in not.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        if 1 != self.__state:&lt;br /&gt;
            return 0&lt;br /&gt;
       &lt;br /&gt;
        # Put your actions here&lt;br /&gt;
        if self.checkPlayerVehicle( player, vehicle, 0 ):&lt;br /&gt;
            self.StartTimer()&lt;br /&gt;
           &lt;br /&gt;
&lt;br /&gt;
    def StartTimer( self ):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Start the timer if the state allows it and the timer isn&#039;t already started&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        if 1 != self.__state:&lt;br /&gt;
            return 0&lt;br /&gt;
        if not self.updateTimer:&lt;br /&gt;
            #self.mm.info( &amp;quot;Starting timer&amp;quot; )&lt;br /&gt;
            #mm_utils.msg_server( &amp;quot;Starting timer&amp;quot; )&lt;br /&gt;
            self.updateTimer = bf2.Timer(self.onUpdate, 10, 1)&lt;br /&gt;
            self.updateTimer.setRecurring(10)&lt;br /&gt;
        else:&lt;br /&gt;
            #self.mm.info( &amp;quot;Timer already enabled&amp;quot; )&lt;br /&gt;
            #mm_utils.msg_server( &amp;quot;Timer already enabled&amp;quot; )&lt;br /&gt;
            pass&lt;br /&gt;
&lt;br /&gt;
    def StopTimer( self ):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Shutdown the timer&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        if self.updateTimer:&lt;br /&gt;
            #self.mm.info( &amp;quot;Stopping timer&amp;quot; )&lt;br /&gt;
            #mm_utils.msg_server( &amp;quot;Stopping timer&amp;quot; )&lt;br /&gt;
            self.updateTimer.destroy()&lt;br /&gt;
            self.updateTimer = None&lt;br /&gt;
        else:&lt;br /&gt;
            #self.mm.info( &amp;quot;Timer already stopped&amp;quot; )&lt;br /&gt;
            #mm_utils.msg_server( &amp;quot;Timer already stopped&amp;quot; )&lt;br /&gt;
            pass&lt;br /&gt;
   &lt;br /&gt;
    def checkPlayerVehicle( self, player, vehicle, mode ):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;mode 0 - player just entered vehicle, 1 - timed check&lt;br /&gt;
        if the vehicle class is forbidden:&lt;br /&gt;
            mode 0 - notify player via server message&lt;br /&gt;
            mode 1 - punish player&lt;br /&gt;
        returns True if player is in forbidden vehicle class, False othervise&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
       &lt;br /&gt;
        forbiddenClass = False&lt;br /&gt;
        try:&lt;br /&gt;
            vehicleType = getVehicleType(vehicle.templateName)&lt;br /&gt;
            vehicleDamage = vehicle.getDamage()&lt;br /&gt;
            body=player.getDefaultVehicle()&lt;br /&gt;
            bodyHealth=body.getDamage()&lt;br /&gt;
           &lt;br /&gt;
            #debug&lt;br /&gt;
            #if 1 == mode:&lt;br /&gt;
            #    self.mm.info( &amp;quot;Player %s (health %d) is in %s (class %d, health %d)&amp;quot; % ( player.getName(), bodyHealth, vehicle.templateName, vehicleType, vehicleDamage ) )&lt;br /&gt;
            #    #mm_utils.msg_server( &amp;quot;Player %s (health %d) is in %s (class %d, health %d)&amp;quot; % ( player.getName(), bodyHealth, vehicle.templateName, vehicleType, vehicleDamage ) )&lt;br /&gt;
            #else:&lt;br /&gt;
            #    self.mm.info( &amp;quot;Player %s (health %d) entered %s (class %d, health %d)&amp;quot; % ( player.getName(), bodyHealth, vehicle.templateName, vehicleType, vehicleDamage ) )&lt;br /&gt;
            #    #mm_utils.msg_server( &amp;quot;Player %s (health %d) entered %s (class %d, health %d)&amp;quot; % ( player.getName(), bodyHealth, vehicle.templateName, vehicleType, vehicleDamage ) )&lt;br /&gt;
           &lt;br /&gt;
            if vehicleType in ForbiddenTypes:&lt;br /&gt;
                forbiddenClass = True&lt;br /&gt;
                if 1 == mode:&lt;br /&gt;
                    #punish&lt;br /&gt;
                    mm_utils.msg_server( &amp;quot;Oh noes %s!&amp;quot; % ( player.getName() ) )&lt;br /&gt;
                    vehicle.setDamage(0.01)&lt;br /&gt;
                    body.setDamage(0.01)&lt;br /&gt;
                else:&lt;br /&gt;
                    #notify&lt;br /&gt;
                    mm_utils.msg_server( &amp;quot;%s entered %s. Somebody set up us the bomb. Get out, QUICK!&amp;quot; % ( player.getName(), vehicle.templateName ) )&lt;br /&gt;
        except:&lt;br /&gt;
            forbiddenClass = False&lt;br /&gt;
           &lt;br /&gt;
        return forbiddenClass&lt;br /&gt;
   &lt;br /&gt;
    def init( self ):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Provides default initialisation.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
       &lt;br /&gt;
        # Register your game handlers and provide any&lt;br /&gt;
        # other dynamic initialisation here&lt;br /&gt;
        self.updateTimer = None&lt;br /&gt;
       &lt;br /&gt;
        if 0 == self.__state:&lt;br /&gt;
            # Register your host handlers here&lt;br /&gt;
            host.registerHandler( &#039;EnterVehicle&#039;, self.onEnterVehicle, 1 )&lt;br /&gt;
           &lt;br /&gt;
        # Update to the running state&lt;br /&gt;
        self.__state = 1&lt;br /&gt;
       &lt;br /&gt;
        # start the timer: if the module was reset during the game at least one check will be made&lt;br /&gt;
        # if no players are in forbidden vehicles the timer will shut down until someone enters one&lt;br /&gt;
        self.StartTimer()&lt;br /&gt;
       &lt;br /&gt;
    def onUpdate( self, data ):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;timed check of all players&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        if 1 != self.__state:&lt;br /&gt;
            return&lt;br /&gt;
               &lt;br /&gt;
        needTimer = False&lt;br /&gt;
        for player in bf2.playerManager.getPlayers():&lt;br /&gt;
            try:&lt;br /&gt;
                vehicle=player.getVehicle();&lt;br /&gt;
                if self.checkPlayerVehicle(player, vehicle, 1): needTimer = True&lt;br /&gt;
            except:&lt;br /&gt;
                try:&lt;br /&gt;
                    player_name = player.getName()&lt;br /&gt;
                except:&lt;br /&gt;
                    player_name = &#039;unknown&#039;&lt;br /&gt;
                self.mm.error( &amp;quot;Failed to check player &#039;%s&#039;&amp;quot; % player_name, True )&lt;br /&gt;
               &lt;br /&gt;
        #do we still need the timer (at least 1 player in a forbidden class vehicle)?&lt;br /&gt;
        if needTimer:&lt;br /&gt;
            self.StartTimer()&lt;br /&gt;
        else:&lt;br /&gt;
            self.StopTimer()&lt;br /&gt;
       &lt;br /&gt;
    def shutdown( self ):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Shutdown and stop processing.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
        # Unregister game handlers and do any other&lt;br /&gt;
        # other actions to ensure your module no longer affects&lt;br /&gt;
        # the game in anyway&lt;br /&gt;
       &lt;br /&gt;
        #stop the timer&lt;br /&gt;
        self.StopTimer&lt;br /&gt;
        # Flag as shutdown as there is currently way to:&lt;br /&gt;
        # host.unregisterHandler&lt;br /&gt;
        self.__state = 2&lt;br /&gt;
&lt;br /&gt;
    def update( self ):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Process and update.&lt;br /&gt;
        Note: This is called VERY often processing in here should&lt;br /&gt;
        be kept to an absolute minimum.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        pass&lt;br /&gt;
&lt;br /&gt;
def mm_load( modManager ):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Creates and returns your object.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    return NoFly( modManager )&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Pireax</name></author>
	</entry>
	<entry>
		<id>https://bf2tech.uturista.pt/index.php?title=Scripts:BF2Oldschool&amp;diff=120</id>
		<title>Scripts:BF2Oldschool</title>
		<link rel="alternate" type="text/html" href="https://bf2tech.uturista.pt/index.php?title=Scripts:BF2Oldschool&amp;diff=120"/>
		<updated>2018-06-22T15:34:09Z</updated>

		<summary type="html">&lt;p&gt;Pireax: Created page with &amp;quot;__TOC__ == Introduction  ==  Today infantry game is strictly connected to official rules that are in ClanBase or ESL. Many of ranked or waib servers put in thier rules: no unl...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
== Introduction  ==&lt;br /&gt;
&lt;br /&gt;
Today infantry game is strictly connected to official rules that are in ClanBase or ESL. Many of ranked or waib servers put in thier rules: no unlocks, no commanders, co c4 etc. But as always only human administrator can prevent people from n00bs that are using forbidden candys. So i created this script to do this automaticly!&lt;br /&gt;
&lt;br /&gt;
== Features  ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Battlefield 2 Oldschool Infantry Script&#039;&#039;&#039;&#039;&#039; can offer:&lt;br /&gt;
&lt;br /&gt;
* Detect weapons on server, based on four diffrent levels &#039;&#039;&#039;NO MEDICS(with unlocks), NO MEDICS(without unlocks), KNIFE-PISTOL-SHOCKPADDLE ONLY, NO UNLOCKS &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
** Also detect misc weapons like: &#039;&#039;&#039;C4, CLAYMORE, Mounted MGS (stationary) and TOW Missle&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Restriction with three modes:&lt;br /&gt;
&lt;br /&gt;
** Only inform player that his weapon is forbidden&lt;br /&gt;
** Kill player just after respawn with forbidden weapon&lt;br /&gt;
** Kick player after specified number of frags with forbidden weapon&lt;br /&gt;
&lt;br /&gt;
* Detect commander&lt;br /&gt;
&lt;br /&gt;
** Only info about new commander&lt;br /&gt;
** Kick commander&lt;br /&gt;
&lt;br /&gt;
* Almoust all settings of this script can be modified on the fly via custom rcon command (it works in game console!)&lt;br /&gt;
&lt;br /&gt;
== Install  ==&lt;br /&gt;
&lt;br /&gt;
* Go to mods/bf2/python/game/ direcory located on your server (ex. BF2_v1.1.2965/mods/bf2/python/game/)&lt;br /&gt;
* Paste there bf2_oldschool.py file&lt;br /&gt;
* Edit __init__.py file and add this two lines:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
import bf2_oldschool&lt;br /&gt;
bf2_oldschool.init()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Restart/run your server&lt;br /&gt;
&lt;br /&gt;
== Configuration  ==&lt;br /&gt;
&lt;br /&gt;
Look inside bf2_oldschool.py file.&lt;br /&gt;
There is all what you need to configure and use this script.&lt;br /&gt;
&lt;br /&gt;
== Code  ==&lt;br /&gt;
&lt;br /&gt;
=== Download  ===&lt;br /&gt;
&lt;br /&gt;
Follow this link to download always the latest version&lt;br /&gt;
Primary download: [http://vis-clan.pl/index.php?file=Download&amp;amp;op=description&amp;amp;dl_id=5 here]&lt;br /&gt;
&lt;br /&gt;
=== Readable  ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
##############################################################################&lt;br /&gt;
#                                                                            #&lt;br /&gt;
#             bf2_oldschool.py - Weapon Punisher by MisiekBest               #&lt;br /&gt;
#                        --- http://vis-clan.pl ---                          #&lt;br /&gt;
#                     --- http://bfo.misiekbest.pl ---                       #&lt;br /&gt;
#                                                                            #&lt;br /&gt;
#    Released: 28.12.2009                                                    #&lt;br /&gt;
#    Script Version: 0.9c                                                    #&lt;br /&gt;
#     Copyright (C) 2009-2010  Michal &#039;MisiekBest&#039; Pawlikowski               #&lt;br /&gt;
#                                                                            #&lt;br /&gt;
#    This program is free software: you can redistribute it and/or modify    #&lt;br /&gt;
#    it under the terms of the GNU General Public License as published by    #&lt;br /&gt;
#    the Free Software Foundation, either version 3 of the License, or       #&lt;br /&gt;
#    any later version.                                                      #&lt;br /&gt;
#                                                                            #&lt;br /&gt;
#    This program is distributed in the hope that it will be useful,         #&lt;br /&gt;
#    but WITHOUT ANY WARRANTY; without even the implied warranty of          #&lt;br /&gt;
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           #&lt;br /&gt;
#    GNU General Public License for more details.                            #&lt;br /&gt;
#                                                                            #&lt;br /&gt;
#    You should have received a copy of the GNU General Public License       #&lt;br /&gt;
#    along with this program.  If not, see http://www.gnu.org/licenses/ .    #&lt;br /&gt;
#                                                                            #&lt;br /&gt;
##############################################################################&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
################&lt;br /&gt;
# What it is?: #&lt;br /&gt;
#########################################################&lt;br /&gt;
# BF2 Oldschool is a Battlefield 2                      #&lt;br /&gt;
# python script made for few things:                    #&lt;br /&gt;
# - Restrict some weapons on server                     #&lt;br /&gt;
# - Kick or kill player for using restricted weapon     #&lt;br /&gt;
# - Kick commander (or just throw info)                 #&lt;br /&gt;
# - Manage script via rcon                              #&lt;br /&gt;
#########################################################&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
###################&lt;br /&gt;
# How to install: #&lt;br /&gt;
##################################################################&lt;br /&gt;
# 1. Go to mods/bf2/python/game/ direcory located on your server #&lt;br /&gt;
# (ex. BF2_v1.1.2965/mods/bf2/python/game/)                      #&lt;br /&gt;
# 2. Paste there this file                                       #&lt;br /&gt;
# 3. Edit __init__.py file and add this two lines:               #&lt;br /&gt;
# import bf2_oldschool                                           #&lt;br /&gt;
# bf2_oldschool.init()                                           #&lt;br /&gt;
# 4. Restart/run your server :)                                  #&lt;br /&gt;
##################################################################&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
###################################&lt;br /&gt;
# How to manage sctipt via rcon?: #&lt;br /&gt;
###############################################################################################&lt;br /&gt;
# This script has &#039;diffrent&#039; manage method. Why diffrent?                                     #&lt;br /&gt;
# Usually admins can manage their scripts using in game chat.                                 #&lt;br /&gt;
# Yes, its easiest way, but not efficient. So i decided to use                                #&lt;br /&gt;
# little hook with rcon &amp;lt;variable&amp;gt;. It will always generate info                              #&lt;br /&gt;
# about error (in game console) but it will work!                                             #&lt;br /&gt;
#                                                                                             #&lt;br /&gt;
# First you must remember to put your/admin&#039;s nickname in settings.                           #&lt;br /&gt;
# Rcon will work only for players that are in ADMIN_LIST.                                     #&lt;br /&gt;
# See ADMIN SETTINGS section for more info.                                                   #&lt;br /&gt;
#                                                                                             #&lt;br /&gt;
# TO RUN COMMAND:                                                                             #&lt;br /&gt;
#                                                                                             #&lt;br /&gt;
# 1. Open your in-game console (by pressing ~ on your keyboard)                               #&lt;br /&gt;
# 2. Every command you must execute using phrase: rcon bfo &amp;lt;command&amp;gt; &amp;lt;optional_value&amp;gt;         #&lt;br /&gt;
#                                                                                             #&lt;br /&gt;
# You can access to this help in game by using &#039;rcon bfo help&#039; command.                       #&lt;br /&gt;
# You can return all main settings by using &#039;rcon bfo status&#039; command.                        #&lt;br /&gt;
#                                                                                             #&lt;br /&gt;
# Here is list of all commands:                                                               #&lt;br /&gt;
# ############## OLDSCHOOL LEVEL ##############                                               #&lt;br /&gt;
# #############################################                                               #&lt;br /&gt;
# olevel         # Return number of oldschool level                                           #&lt;br /&gt;
# olevel [value] # Set oldschool level to given value                                         #&lt;br /&gt;
#                                                                                             #&lt;br /&gt;
# ############## PUNISH METHOD  ##############                                                #&lt;br /&gt;
# ############################################                                                #&lt;br /&gt;
# punish         # Return number of punish method                                             #&lt;br /&gt;
# punish [value] # Set punish method to given value                                           #&lt;br /&gt;
#                                                                                             #&lt;br /&gt;
# ##############   MISC WEAPONS   ##############                                              #&lt;br /&gt;
# ##############################################                                              #&lt;br /&gt;
# c4         # Return status of C4 restriction                                                #&lt;br /&gt;
# c4 [value] # Enable or disble C4 restriction. 0-Disable  1-Enable                           #&lt;br /&gt;
# claymore         # Return status of CLAYMORE restriction                                    #&lt;br /&gt;
# claymore [value] # Enable or disble CLAYMORE restriction. 0-Disable  1-Enable               #&lt;br /&gt;
# mgs         # Return status of MOUNTED MGS restriction                                      #&lt;br /&gt;
# mgs [value] # Enable or disble MOUNTED MGS restriction. 0-Disable  1-Enable                 #&lt;br /&gt;
# tow         # Return status of TOW MISSILE restriction                                      #&lt;br /&gt;
# tow [value] # Enable or disble TOW MISSILE restriction. 0-Disable  1-Enable                 #&lt;br /&gt;
#                                                                                             #&lt;br /&gt;
# ##############   KICKER SYSTEM (punish 2)   ##############                                  #&lt;br /&gt;
# ##########################################################                                  #&lt;br /&gt;
# kick_frags         # Return number of how many kills from restricted weapon to kick player  #&lt;br /&gt;
# kick_frags [value] # Set HOW_MANY_KILLS_TO_KICK to given value                              #&lt;br /&gt;
# kick_time          # Return minutes for how long player should be kicked out.               #&lt;br /&gt;
# kick_time [value]  # Set minutes for how long player should be kicked out.                  #&lt;br /&gt;
#                                                                                             #&lt;br /&gt;
# ##############    ANTI COMMANDER    ##############                                          #&lt;br /&gt;
# ##################################################                                          #&lt;br /&gt;
# anticomm           # Return status of ANTICOMMANDER system                                  #&lt;br /&gt;
# anticomm [value]   # Enable or disble commander restriction. 0-Disable  1-Enable            #&lt;br /&gt;
# commkick           # Return status of COMMANDER KICKER system                               #&lt;br /&gt;
# commkick [value]   # Enable or disble commander kicking. 0-Disable  1-Enable                #&lt;br /&gt;
# commkick_time          # Return minutes for how long commander should be kicked out.        #&lt;br /&gt;
# commkick_time [value]  # Set minutes for how long commander should be kicked out.           #&lt;br /&gt;
#                                                                                             #&lt;br /&gt;
#                                                                                             #&lt;br /&gt;
###############################################################################################&lt;br /&gt;
&lt;br /&gt;
CHANGELOG:&lt;br /&gt;
&lt;br /&gt;
0.9c:&lt;br /&gt;
- Added &amp;quot;NO SNIPERS&amp;quot; restriction mode (OLDSCHOOL_LEVEL = 6)&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
################################################################################&lt;br /&gt;
################################################################################&lt;br /&gt;
##-&amp;gt;                        GLOBAL CONFIGURATION                            &amp;lt;-##&lt;br /&gt;
################################################################################&lt;br /&gt;
################################################################################&lt;br /&gt;
&lt;br /&gt;
###################&lt;br /&gt;
# OLDSCHOOL LEVEL #&lt;br /&gt;
#################################################################################################&lt;br /&gt;
# Here you can decide which group of weapons should be restricted                               #&lt;br /&gt;
# Set OLDSCHOOL_LEVEL to one of these values:                                                   #&lt;br /&gt;
# 0 - Completly disable script!                                                                 #&lt;br /&gt;
# 1 - MEDICS ONLY (with med unlocks!)                                                           #&lt;br /&gt;
# 2 - MEDICS ONLY (without med unlocks!)                                                        #&lt;br /&gt;
# 3 - KNIFE, PISTOL, SHOCKPADDLE (only these weapons are allowed! Other will be punished.       #&lt;br /&gt;
#     (NOTE: OLDSCHOOL LEVEL 3 WILL WORK ONLY WITH PUNISH METHOD 2 (kicking)!!!)                #&lt;br /&gt;
# 4 - NO UNLOCKS (all kits but without unlocks)                                                 #&lt;br /&gt;
# 5 - NO OLDSCHOOL LEVEL, JUST USE OTHER SETTINGS (in.ex.: anticommander or c4, claymore etc.)  #&lt;br /&gt;
# 6 - NO SNIPERS                                                                                #&lt;br /&gt;
#################################################################################################&lt;br /&gt;
OLDSCHOOL_LEVEL = 6&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
###################&lt;br /&gt;
#   MISC WEAPONS  #&lt;br /&gt;
#####################################################################&lt;br /&gt;
# Here you can enable or disable punishing for using                #&lt;br /&gt;
# miscellaneous wapons: c4, claymore, stationary mgs and tow missle #&lt;br /&gt;
# Set each variable to 0 or 1                                       #&lt;br /&gt;
# 0 - DISABLE                                                       #&lt;br /&gt;
# 1 - ENABLE                                                        #&lt;br /&gt;
#####################################################################&lt;br /&gt;
NO_C4 = 0&lt;br /&gt;
NO_CLAYMORE = 1&lt;br /&gt;
NO_MOUNTED_MGS = 0 #NOTE: WORKS ONLY WITH PUNISH METHOD 2&lt;br /&gt;
NO_TOW_MISSILE = 0 #NOTE: WORKS ONLY WITH PUNISH METHOD 2&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
####################&lt;br /&gt;
#   PUNISH METHOD  #&lt;br /&gt;
####################################################################################################################&lt;br /&gt;
# Here you can choose how player should be punished for using restricted weapon.                                   #&lt;br /&gt;
# Set PUNISH_METHOD to one of these values:                                                                        #&lt;br /&gt;
# 0 - NO PUNISH, ONLY WARNING. Warning can be set in WARNING_LVL0 (put %s for player name)                         #&lt;br /&gt;
#     NOTE: this will produce massive spam if player                                                               #&lt;br /&gt;
#     will start switching weapons for example from allowed pistol to forbidden                                    #&lt;br /&gt;
#     g36e, then pistol and then again g36e etc.                                                                   #&lt;br /&gt;
#                                                                                                                  #&lt;br /&gt;
# 1 - KILL PLAYER JUST AFTER RESPAWN WITH FORBIDDEN WEAPON.                                                        #&lt;br /&gt;
#     Killing msg can be set in WARNING_LVL1 (put %s for player name)                                              #&lt;br /&gt;
#     NOTE: if c4 or clay is forbidden player will be punished after                                               #&lt;br /&gt;
#     switching to them by pressing 5 or 6 key                                                                     #&lt;br /&gt;
#                                                                                                                  #&lt;br /&gt;
# 2 - KICK PLAYER AFTER HOW_MANY_KILLS_TO_KICK TIMES                                                               #&lt;br /&gt;
#     (PUNKBUSTER PROTECTION MUST BE ENABLED!)                                                                     #&lt;br /&gt;
#     Here you can also set few things:                                                                            #&lt;br /&gt;
#     HOW_MANY_KILLS_TO_KICK - After how many frags player should be kicked out?                                   #&lt;br /&gt;
#                                                                                                                  #&lt;br /&gt;
#     WARNING_AFTER_FRAG - This message will appear when player kill somebody with forbidden weapon                #&lt;br /&gt;
#                          (put %s for player name)                                                                #&lt;br /&gt;
#                                                                                                                  #&lt;br /&gt;
#     RESTRICTED_WEAPON_KICK_MSG - This msg appears in game when script is kicking player (put %s for player name) #&lt;br /&gt;
#                                                                                                                  #&lt;br /&gt;
#     RESTRICTED_WEAPON_KICK_REASON - This msg gets player after kick - in cool punkbuster window :)               #&lt;br /&gt;
#                                                                                                                  #&lt;br /&gt;
#     RESTRICTED_WEAPON_KICK_IN_MINUTES - Here you can decide for how long player should be kicked. Use wisely ;)  #&lt;br /&gt;
####################################################################################################################&lt;br /&gt;
PUNISH_METHOD = 2&lt;br /&gt;
&lt;br /&gt;
#######################################&lt;br /&gt;
#     PUNISH METHOD 0 - CONFIG        #&lt;br /&gt;
#######################################&lt;br /&gt;
WARNING_LVL0 = &amp;quot;Warning %s ! Do not use this weapon! Its forbidden!&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#######################################&lt;br /&gt;
#     PUNISH METHOD 1 - CONFIG        #&lt;br /&gt;
#######################################&lt;br /&gt;
WARNING_LVL1 = &amp;quot;Warning %s ! You have been killed for using restricted weapon!&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#######################################&lt;br /&gt;
#     PUNISH METHOD 2 - CONFIG        #&lt;br /&gt;
#######################################&lt;br /&gt;
HOW_MANY_KILLS_TO_KICK = 2&lt;br /&gt;
WARNING_AFTER_FRAG = &amp;quot;Warning %s ! This weapon is forbidden! Stop being a n00b or you will get kicked!&amp;quot;&lt;br /&gt;
RESTRICTED_WEAPON_KICK_MSG = &amp;quot;Kicking %s for using restricted weapons!&amp;quot;&lt;br /&gt;
RESTRICTED_WEAPON_KICK_REASON = &amp;quot;You have been kicked for using restricted weapons!&amp;quot;&lt;br /&gt;
RESTRICTED_WEAPON_KICK_IN_MINUTES = 10&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#####################&lt;br /&gt;
#   ANTI COMMANDER  #&lt;br /&gt;
#############################################################################################################&lt;br /&gt;
# Here you can enable or disable commander protection.                                                      #&lt;br /&gt;
# Module can be enabled with ANTICOMMANDER set to 1. Use 0 to disable it.                                   #&lt;br /&gt;
# Warning can be set in COMMANDER_MSG (put %s for player name)                                              #&lt;br /&gt;
#                                                                                                           #&lt;br /&gt;
# Instead of &#039;only info&#039; you can enable commander kicking by switching COMMANDER_AUTOKICK to 1              #&lt;br /&gt;
# Then you can set other things:                                                                            #&lt;br /&gt;
#                                                                                                           #&lt;br /&gt;
# COMMANDER_KICK_TIME_IN_MINUTES - For how long commander should be kicked out?                             #&lt;br /&gt;
#                                                                                                           #&lt;br /&gt;
# COMMANDER_KICK_MSG - This msg appears in game when script is kicking commander (put %s for player name)   #&lt;br /&gt;
#                                                                                                           #&lt;br /&gt;
# COMMANDER_KICK_REASON - This msg gets player after kick - of course in cool punkbuster window ;)          #&lt;br /&gt;
#############################################################################################################&lt;br /&gt;
ANTICOMMANDER = 0&lt;br /&gt;
COMMANDER_MSG = &amp;quot;Warning! Player %s became a commander!&amp;quot;&lt;br /&gt;
&lt;br /&gt;
COMMANDER_AUTOKICK = 0&lt;br /&gt;
COMMANDER_KICK_TIME_IN_MINUTES = 2&lt;br /&gt;
COMMANDER_KICK_MSG = &amp;quot;Kicking %s for using commander!&amp;quot;&lt;br /&gt;
COMMANDER_KICK_REASON = &amp;quot;You have been kicked for using commander!&amp;quot;&lt;br /&gt;
&lt;br /&gt;
######################&lt;br /&gt;
#   ADMIN SETTINGS   #&lt;br /&gt;
###########################################################################################&lt;br /&gt;
# Here you can set new admin(s) for rcon administration of this script.                   #&lt;br /&gt;
# Just put his/her name in &amp;quot; &amp;quot; (dont forget about prefix!). Add comma if more then one ;] #&lt;br /&gt;
# example: ADMIN_LIST = &amp;quot;[V!S] MisiekBest[PL]&amp;quot;, &amp;quot;#SOF# FrYzJeR.inf&amp;quot;                       #&lt;br /&gt;
###########################################################################################&lt;br /&gt;
ADMIN_LIST = &amp;quot;[V!S] MisiekBest[PL]&amp;quot;, &amp;quot;#NM# MisiekBest[PL]&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
################################################################################&lt;br /&gt;
################################################################################&lt;br /&gt;
##-&amp;gt;                     END OF GLOBAL CONFIGURATION                        &amp;lt;-##&lt;br /&gt;
##-&amp;gt;                    DONT CHANGE ANYTHING BELOW ;)                       &amp;lt;-##&lt;br /&gt;
################################################################################&lt;br /&gt;
################################################################################&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
import bf2&lt;br /&gt;
import host&lt;br /&gt;
_MED_ONLY_FW_ = &amp;quot;usrif_m4&amp;quot;,&amp;quot;usrif_m24&amp;quot;,&amp;quot;usrif_m203&amp;quot;,&amp;quot;uslmg_m249saw&amp;quot;,&amp;quot;usrif_remington11-87&amp;quot;,&amp;quot;usrif_mp5_a3&amp;quot;,&amp;quot;usrgl_m203&amp;quot;,&amp;quot;usatp_predator&amp;quot;,&amp;quot;c4_explosives&amp;quot;,&amp;quot;usmin_claymore&amp;quot;,&amp;quot;at_mine&amp;quot;,&amp;quot;rurrif_ak74u&amp;quot;,&amp;quot;rurif_dragunov&amp;quot;,&amp;quot;rurif_gp30&amp;quot;,&amp;quot;rulmg_rpk74&amp;quot;,&amp;quot;rusht_saiga12&amp;quot;,&amp;quot;rurif_bizon&amp;quot;,&amp;quot;rurgl_gp30&amp;quot;,&amp;quot;chat_eryx&amp;quot;,&amp;quot;chrif_type95&amp;quot;,&amp;quot;chsni_type88&amp;quot;,&amp;quot;rurif_gp25&amp;quot;,&amp;quot;chlmg_type95&amp;quot;,&amp;quot;chsht_norinco982&amp;quot;,&amp;quot;chrif_type85&amp;quot;,&amp;quot;rurgl_gp25&amp;quot;,&amp;quot;usrif_g36c&amp;quot;,&amp;quot;ussni_m95_barret&amp;quot;,&amp;quot;usrif_g3a3&amp;quot;,&amp;quot;rulmg_pkm&amp;quot;,&amp;quot;ussht_jackhammer&amp;quot;,&amp;quot;chsht_protecta&amp;quot;,&amp;quot;usrif_fnscarl&amp;quot;,&amp;quot;gbrif_l96a1&amp;quot;,&amp;quot;sasrif_fn2000&amp;quot;,&amp;quot;sasgr_fn2000&amp;quot;,&amp;quot;sasrif_mg36&amp;quot;,&amp;quot;sasrif_mp7&amp;quot;,&amp;quot;eurif_fnp90&amp;quot;&lt;br /&gt;
_MED_ONLY_NO_UN_FW_ = &amp;quot;usrif_m4&amp;quot;,&amp;quot;usrif_m24&amp;quot;,&amp;quot;usrif_m203&amp;quot;,&amp;quot;uslmg_m249saw&amp;quot;,&amp;quot;usrif_remington11-87&amp;quot;,&amp;quot;usrif_mp5_a3&amp;quot;,&amp;quot;usrgl_m203&amp;quot;,&amp;quot;usatp_predator&amp;quot;,&amp;quot;c4_explosives&amp;quot;,&amp;quot;usmin_claymore&amp;quot;,&amp;quot;at_mine&amp;quot;,&amp;quot;rurrif_ak74u&amp;quot;,&amp;quot;rurif_dragunov&amp;quot;,&amp;quot;rurif_gp30&amp;quot;,&amp;quot;rulmg_rpk74&amp;quot;,&amp;quot;rusht_saiga12&amp;quot;,&amp;quot;rurif_bizon&amp;quot;,&amp;quot;rurgl_gp30&amp;quot;,&amp;quot;chat_eryx&amp;quot;,&amp;quot;chrif_type95&amp;quot;,&amp;quot;chsni_type88&amp;quot;,&amp;quot;rurif_gp25&amp;quot;,&amp;quot;chlmg_type95&amp;quot;,&amp;quot;chsht_norinco982&amp;quot;,&amp;quot;chrif_type85&amp;quot;,&amp;quot;rurgl_gp25&amp;quot;,&amp;quot;usrif_g36c&amp;quot;,&amp;quot;ussni_m95_barret&amp;quot;,&amp;quot;usrif_g3a3&amp;quot;,&amp;quot;rulmg_pkm&amp;quot;,&amp;quot;ussht_jackhammer&amp;quot;,&amp;quot;chsht_protecta&amp;quot;,&amp;quot;usrif_fnscarl&amp;quot;,&amp;quot;gbrif_l96a1&amp;quot;,&amp;quot;sasrif_fn2000&amp;quot;,&amp;quot;sasgr_fn2000&amp;quot;,&amp;quot;sasrif_mg36&amp;quot;,&amp;quot;sasrif_mp7&amp;quot;,&amp;quot;eurif_fnp90&amp;quot;,&amp;quot;usrif_sa80&amp;quot;,&amp;quot;sasrif_g36e&amp;quot;&lt;br /&gt;
_KPS_ONLY_AW_ = &amp;quot;kni_knife&amp;quot;,&amp;quot;uspis_92fs_silencer&amp;quot;,&amp;quot;uspis_92fs&amp;quot;,&amp;quot;rupis_baghira_silencer&amp;quot;,&amp;quot;rupis_baghira&amp;quot;,&amp;quot;chpis_qsz92_silencer&amp;quot;,&amp;quot;chpis_qsz92&amp;quot;&lt;br /&gt;
_NO_UNLOCKS_FW_ = &amp;quot;usrif_g36c&amp;quot;,&amp;quot;ussni_m95_barret&amp;quot;,&amp;quot;usrif_g3a3&amp;quot;,&amp;quot;rulmg_pkm&amp;quot;,&amp;quot;ussht_jackhammer&amp;quot;,&amp;quot;usrif_sa80&amp;quot;,&amp;quot;chsht_protecta&amp;quot;,&amp;quot;usrif_fnscarl&amp;quot;,&amp;quot;gbrif_l96a1&amp;quot;,&amp;quot;sasrif_fn2000&amp;quot;,&amp;quot;sasgr_fn2000&amp;quot;,&amp;quot;sasrif_mg36&amp;quot;,&amp;quot;sasrif_mp7&amp;quot;,&amp;quot;sasrif_g36e&amp;quot;,&amp;quot;eurif_fnp90&amp;quot;&lt;br /&gt;
_NO_SNIPERS_ = &amp;quot;usrif_m24&amp;quot;,&amp;quot;rurif_dragunov&amp;quot;,&amp;quot;chsni_type88&amp;quot;, &amp;quot;ussni_m95_barret&amp;quot;, &amp;quot;gbrif_l96a1&amp;quot;&lt;br /&gt;
playerKickList = []&lt;br /&gt;
def init():&lt;br /&gt;
    global OLDSCHOOL_LEVEL, PUNISH_METHOD, ANTICOMMANDER&lt;br /&gt;
    if (OLDSCHOOL_LEVEL != 0):&lt;br /&gt;
        if (ANTICOMMANDER == 1): host.registerHandler(&#039;ChangedCommander&#039;, onCommander, 1)&lt;br /&gt;
        if (PUNISH_METHOD == 2): host.registerHandler(&#039;PlayerKilled&#039;, onPlayerKilled, 1)&lt;br /&gt;
        if (PUNISH_METHOD == 0 or (PUNISH_METHOD == 1 and OLDSCHOOL_LEVEL != 3)): host.registerHandler(&#039;PlayerChangeWeapon&#039;, onPlayerChangeWeapon, 1)&lt;br /&gt;
        host.registerHandler(&#039;RemoteCommand&#039;, onRemoteCommand, 1)&lt;br /&gt;
        host.registerGameStatusHandler(onGameStatusChange)&lt;br /&gt;
        host.rcon_invoke(&#039;echo &amp;quot;bf2_oldschool.py by MisiekBest loaded&amp;quot;&#039;)&lt;br /&gt;
    else:&lt;br /&gt;
        host.rcon_invoke(&#039;echo &amp;quot;bf2_oldschool.py by MisiekBest loaded, script DISABLED by config!&amp;quot;&#039;)&lt;br /&gt;
&lt;br /&gt;
def onCommander(teamid, oldCommanderPlayerObject, player):&lt;br /&gt;
        global OLDSCHOOL_LEVEL&lt;br /&gt;
        if (OLDSCHOOL_LEVEL != 0):   &lt;br /&gt;
            global ANTICOMMANDER&lt;br /&gt;
            if (ANTICOMMANDER): #yeap. Double check. Unfortunately DICE forgot to implement host.UNregisterHandler... And this is the only way to disable anticommander (and other) &#039;on the fly&#039; by using remote rcon command. Sorry :P&lt;br /&gt;
                global COMMANDER_AUTOKICK&lt;br /&gt;
                if (COMMANDER_AUTOKICK == 1):&lt;br /&gt;
                    global COMMANDER_KICK_MSG, COMMANDER_KICK_REASON, COMMANDER_KICK_TIME_IN_MINUTES&lt;br /&gt;
                    host.sgl_sendTextMessage( 0, 12, 1, str(COMMANDER_KICK_MSG)  % (player.getName()), 0)&lt;br /&gt;
                    host.rcon_invoke(&amp;quot;pb_sv_kick \&amp;quot;&amp;quot;+str(player.getName())+&amp;quot;\&amp;quot; &amp;quot;+str(COMMANDER_KICK_TIME_IN_MINUTES)+&amp;quot; \&amp;quot;&amp;quot;+str(COMMANDER_KICK_REASON)+&amp;quot;\&amp;quot;&amp;quot;)&lt;br /&gt;
                else:&lt;br /&gt;
                    global COMMANDER_MSG&lt;br /&gt;
                    host.sgl_sendTextMessage( 0, 12, 1, str(COMMANDER_MSG)  % (player.getName()), 0)&lt;br /&gt;
                    host.sgl_sendTextMessage( 0, 12, 1, str(COMMANDER_MSG)  % (player.getName()), 0)&lt;br /&gt;
                    host.sgl_sendTextMessage( 0, 12, 1, str(COMMANDER_MSG)  % (player.getName()), 0)&lt;br /&gt;
                    host.sgl_sendTextMessage( 0, 12, 1, str(COMMANDER_MSG)  % (player.getName()), 0)&lt;br /&gt;
                    host.sgl_sendTextMessage( 0, 12, 1, str(COMMANDER_MSG)  % (player.getName()), 0)&lt;br /&gt;
&lt;br /&gt;
def onPlayerKilled(victim, attacker, weapon, assists, victimSoldierObject):&lt;br /&gt;
    global OLDSCHOOL_LEVEL&lt;br /&gt;
    if (OLDSCHOOL_LEVEL != 0):&lt;br /&gt;
        global PUNISH_METHOD&lt;br /&gt;
        if (PUNISH_METHOD == 2):&lt;br /&gt;
            global NO_C4, NO_CLAYMORE, NO_MOUNTED_MGS, NO_TOW_MISSILE&lt;br /&gt;
            if OLDSCHOOL_LEVEL == 1:&lt;br /&gt;
                global _MED_ONLY_FW_&lt;br /&gt;
                checkAndJudge(_MED_ONLY_FW_,attacker,weapon,0)&lt;br /&gt;
            elif OLDSCHOOL_LEVEL == 2:&lt;br /&gt;
                global _MED_ONLY_NO_UN_FW_&lt;br /&gt;
                checkAndJudge(_MED_ONLY_NO_UN_FW_,attacker,weapon,0)&lt;br /&gt;
            elif OLDSCHOOL_LEVEL == 3:&lt;br /&gt;
                global _KPS_ONLY_AW_&lt;br /&gt;
                checkAndJudge(_KPS_ONLY_AW_,attacker,weapon,1)&lt;br /&gt;
            elif OLDSCHOOL_LEVEL == 4:&lt;br /&gt;
                global _NO_UNLOCKS_FW_&lt;br /&gt;
                checkAndJudge(_NO_UNLOCKS_FW_,attacker,weapon,0)&lt;br /&gt;
            elif OLDSCHOOL_LEVEL == 5:&lt;br /&gt;
                pass&lt;br /&gt;
            elif OLDSCHOOL_LEVEL == 6:&lt;br /&gt;
                global _NO_SNIPERS_&lt;br /&gt;
                checkAndJudge(_NO_SNIPERS_,attacker,weapon,0)&lt;br /&gt;
            else:&lt;br /&gt;
                pass&lt;br /&gt;
               &lt;br /&gt;
               &lt;br /&gt;
            if NO_C4 or NO_CLAYMORE or NO_MOUNTED_MGS or NO_TOW_MISSILE: checkAndJudgeMisc(attacker, weapon)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def onPlayerChangeWeapon(player, oldWeapon, weapon):&lt;br /&gt;
    global OLDSCHOOL_LEVEL, PUNISH_METHOD&lt;br /&gt;
    if (OLDSCHOOL_LEVEL != 0):&lt;br /&gt;
        if (PUNISH_METHOD == 0 or (PUNISH_METHOD == 1 and OLDSCHOOL_LEVEL != 3)):   &lt;br /&gt;
            global NO_C4, NO_CLAYMORE, NO_MOUNTED_MGS, NO_TOW_MISSILE&lt;br /&gt;
            if OLDSCHOOL_LEVEL == 1:&lt;br /&gt;
                global _MED_ONLY_FW_&lt;br /&gt;
                changedWeapon(_MED_ONLY_FW_,player,weapon,0)&lt;br /&gt;
            elif OLDSCHOOL_LEVEL == 2:&lt;br /&gt;
                global _MED_ONLY_NO_UN_FW_&lt;br /&gt;
                changedWeapon(_MED_ONLY_NO_UN_FW_,player,weapon,0)&lt;br /&gt;
            elif OLDSCHOOL_LEVEL == 3:&lt;br /&gt;
                global _KPS_ONLY_AW_&lt;br /&gt;
                changedWeapon(_KPS_ONLY_AW_,player,weapon,1)&lt;br /&gt;
            elif OLDSCHOOL_LEVEL == 4:&lt;br /&gt;
                global _NO_UNLOCKS_FW_&lt;br /&gt;
                changedWeapon(_NO_UNLOCKS_FW_,player,weapon,0)&lt;br /&gt;
            elif OLDSCHOOL_LEVEL == 5:&lt;br /&gt;
                pass&lt;br /&gt;
            elif OLDSCHOOL_LEVEL == 6:&lt;br /&gt;
                global _NO_SNIPERS_&lt;br /&gt;
                changedWeapon(_NO_SNIPERS_,player,weapon,0)&lt;br /&gt;
            else:&lt;br /&gt;
                pass&lt;br /&gt;
               &lt;br /&gt;
               &lt;br /&gt;
            if NO_C4 or NO_CLAYMORE or NO_MOUNTED_MGS or NO_TOW_MISSILE: changedWeaponMisc(player, weapon)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def sayAll(msg):&lt;br /&gt;
    host.rcon_invoke(&amp;quot;game.sayAll \&amp;quot;&amp;quot; + str(msg) + &amp;quot;\&amp;quot;&amp;quot;)&lt;br /&gt;
   &lt;br /&gt;
&lt;br /&gt;
def onRemoteCommand(playerId, cmd):&lt;br /&gt;
    playerObject =  bf2.playerManager.getPlayerByIndex(playerId)&lt;br /&gt;
    playerName = playerObject.getName()&lt;br /&gt;
    global ADMIN_LIST&lt;br /&gt;
    if (str(playerName) in ADMIN_LIST):&lt;br /&gt;
        execRconCmd(cmd)&lt;br /&gt;
   &lt;br /&gt;
def checkAndJudge(WeaponList,attacker,weapon,method):&lt;br /&gt;
    if not (method):&lt;br /&gt;
        if (str(weapon.templateName) in WeaponList): KickerSystem(attacker)&lt;br /&gt;
    else:&lt;br /&gt;
        if not (str(weapon.templateName) in WeaponList): KickerSystem(attacker)&lt;br /&gt;
&lt;br /&gt;
def checkAndJudgeMisc(attacker, weapon):&lt;br /&gt;
    global NO_C4, NO_CLAYMORE, NO_MOUNTED_MGS, NO_TOW_MISSILE&lt;br /&gt;
    if ((NO_CLAYMORE and weapon.templateName == &amp;quot;usmin_claymore&amp;quot;) or (NO_C4 and weapon.templateName == &amp;quot;c4_explosives&amp;quot;) or (NO_MOUNTED_MGS and weapon.templateName == &amp;quot;rulmg_rpk74_stationary&amp;quot;) or (NO_TOW_MISSILE and weapon.templateName == &amp;quot;ats_hj8_Launcher&amp;quot;)): KickerSystem(attacker)&lt;br /&gt;
   &lt;br /&gt;
def KickerSystem(player):&lt;br /&gt;
    global playerKickList, HOW_MANY_KILLS_TO_KICK, RESTRICTED_WEAPON_KICK_MSG, RESTRICTED_WEAPON_KICK_REASON, WARNING_AFTER_FRAG, RESTRICTED_WEAPON_KICK_IN_MINUTES&lt;br /&gt;
    playerId = player.getProfileId()&lt;br /&gt;
    t = 0&lt;br /&gt;
    for temp_player in playerKickList:&lt;br /&gt;
        if (int(playerId) == int(temp_player[0])):&lt;br /&gt;
            temp_player[1]+=1;&lt;br /&gt;
            if (temp_player[1] &amp;gt;= HOW_MANY_KILLS_TO_KICK):&lt;br /&gt;
                host.sgl_sendTextMessage( 0, 12, 1, str(RESTRICTED_WEAPON_KICK_MSG)  % (player.getName()), 0)&lt;br /&gt;
                host.rcon_invoke(&amp;quot;pb_sv_kick \&amp;quot;&amp;quot;+str(player.getName())+&amp;quot;\&amp;quot; &amp;quot;+str(RESTRICTED_WEAPON_KICK_IN_MINUTES)+&amp;quot; \&amp;quot;&amp;quot;+str(RESTRICTED_WEAPON_KICK_REASON)+&amp;quot;\&amp;quot;&amp;quot;)&lt;br /&gt;
                del playerKickList[playerKickList.index([playerId,temp_player[1]])]&lt;br /&gt;
                t = 1&lt;br /&gt;
               &lt;br /&gt;
            else:&lt;br /&gt;
                host.sgl_sendTextMessage( 0, 12, 1, str(WARNING_AFTER_FRAG)  % (player.getName()), 0)&lt;br /&gt;
                t = 1&lt;br /&gt;
           &lt;br /&gt;
    if not (t):&lt;br /&gt;
        playerKickList.append([playerId, 1])&lt;br /&gt;
        host.sgl_sendTextMessage( 0, 12, 1, str(WARNING_AFTER_FRAG)  % (player.getName()), 0)&lt;br /&gt;
        t = 0&lt;br /&gt;
def changedWeapon(WeaponList, player, weapon, method):&lt;br /&gt;
    global PUNISH_METHOD, WARNING_LVL0, WARNING_LVL1&lt;br /&gt;
    if not (method):&lt;br /&gt;
        if (str(weapon.templateName) in WeaponList):&lt;br /&gt;
            if not (PUNISH_METHOD):&lt;br /&gt;
                host.sgl_sendTextMessage( 0, 12, 1, str(WARNING_LVL0)  % (player.getName()), 0)&lt;br /&gt;
            else:&lt;br /&gt;
                player.getDefaultVehicle().setDamage(0)&lt;br /&gt;
                host.sgl_sendTextMessage( 0, 12, 1, str(WARNING_LVL1)  % (player.getName()), 0)&lt;br /&gt;
    else:&lt;br /&gt;
        if not (str(weapon.templateName) in WeaponList):&lt;br /&gt;
            if not (PUNISH_METHOD):&lt;br /&gt;
                host.sgl_sendTextMessage( 0, 12, 1, str(WARNING_LVL0)  % (player.getName()), 0)&lt;br /&gt;
            else:&lt;br /&gt;
                player.getDefaultVehicle().setDamage(0)&lt;br /&gt;
                host.sgl_sendTextMessage( 0, 12, 1, str(WARNING_LVL1)  % (player.getName()), 0)&lt;br /&gt;
   &lt;br /&gt;
def changedWeaponMisc(player, weapon):&lt;br /&gt;
    global NO_C4, NO_CLAYMORE, NO_MOUNTED_MGS, NO_TOW_MISSILE, PUNISH_METHOD, WARNING_LVL0, WARNING_LVL1&lt;br /&gt;
    if ((NO_CLAYMORE and weapon.templateName == &amp;quot;usmin_claymore&amp;quot;) or (NO_C4 and weapon.templateName == &amp;quot;c4_explosives&amp;quot;) or (NO_MOUNTED_MGS and weapon.templateName == &amp;quot;rulmg_rpk74_stationary&amp;quot;) or (NO_TOW_MISSILE and weapon.templateName == &amp;quot;ats_hj8_Launcher&amp;quot;)):&lt;br /&gt;
        if not (PUNISH_METHOD):&lt;br /&gt;
            host.sgl_sendTextMessage( 0, 12, 1, str(WARNING_LVL0)  % (player.getName()), 0)&lt;br /&gt;
        else:&lt;br /&gt;
            player.getDefaultVehicle().setDamage(0)&lt;br /&gt;
            host.sgl_sendTextMessage( 0, 12, 1, str(WARNING_LVL1)  % (player.getName()), 0)&lt;br /&gt;
           &lt;br /&gt;
def isThirdArg(sc):&lt;br /&gt;
    try:&lt;br /&gt;
        if (sc[0] and sc[1] and sc[2]):&lt;br /&gt;
            return True&lt;br /&gt;
    except IndexError:&lt;br /&gt;
        return False&lt;br /&gt;
       &lt;br /&gt;
def isInt(expression):&lt;br /&gt;
    try:&lt;br /&gt;
        int(expression)&lt;br /&gt;
        return True&lt;br /&gt;
    except ValueError:&lt;br /&gt;
        return False&lt;br /&gt;
       &lt;br /&gt;
def execRconCmd(cmd):&lt;br /&gt;
    sc = str(cmd).split()&lt;br /&gt;
    if (sc[0] == &amp;quot;bfo&amp;quot;):&lt;br /&gt;
        if not (isThirdArg(sc)):&lt;br /&gt;
            if (sc[1] == &amp;quot;status&amp;quot;):&lt;br /&gt;
                global RESTRICTED_WEAPON_KICK_IN_MINUTES, HOW_MANY_KILLS_TO_KICK, OLDSCHOOL_LEVEL, NO_C4, NO_CLAYMORE, NO_MOUNTED_MGS, NO_TOW_MISSILE, PUNISH_METHOD, ANTICOMMANDER, COMMANDER_AUTOKICK, COMMANDER_KICK_TIME_IN_MINUTES&lt;br /&gt;
                host.rcon_invoke(&amp;quot;game.sayAll \&amp;quot;MAIN CONFIG ==&amp;gt; OLDSCHOOL LEVEL: &amp;quot; + str(OLDSCHOOL_LEVEL) + &amp;quot;, PUNISH METHOD: &amp;quot; + str(PUNISH_METHOD) + &amp;quot;, NO CLAYMORE: &amp;quot; + str(NO_CLAYMORE) + &amp;quot;, NO C4: &amp;quot; + str(NO_C4) + &amp;quot;, NO MOUNTED MGS: &amp;quot; + str(NO_MOUNTED_MGS) + &amp;quot;, NO TOW: &amp;quot; + str(NO_TOW_MISSILE) + &amp;quot;\&amp;quot;&amp;quot;)&lt;br /&gt;
                host.rcon_invoke(&amp;quot;game.sayAll \&amp;quot;PUNISH METHOD 2 KICKER SYSTEM ==&amp;gt;  HOW MANY KILLS TO KICK: &amp;quot; + str(HOW_MANY_KILLS_TO_KICK) + &amp;quot;, RESTRICTED WEAPON KICK TIME: &amp;quot; + str(NO_C4) + &amp;quot;min.\&amp;quot;&amp;quot;)&lt;br /&gt;
                host.rcon_invoke(&amp;quot;game.sayAll \&amp;quot;ANTICOMM ==&amp;gt; ANTICOMMANDER: &amp;quot; + str(ANTICOMMANDER) + &amp;quot;, COMMANDER AUTOKICK: &amp;quot; + str(COMMANDER_AUTOKICK) + &amp;quot;, COMMANDER KICK TIME: &amp;quot; + str(COMMANDER_KICK_TIME_IN_MINUTES) + &amp;quot;min.\&amp;quot;&amp;quot;)&lt;br /&gt;
            elif (sc[1] == &amp;quot;punish&amp;quot;):&lt;br /&gt;
                global PUNISH_METHOD&lt;br /&gt;
                host.rcon_invoke(&amp;quot;game.sayAll \&amp;quot;BFO:::      PUNISH METHOD: &amp;quot; + str(PUNISH_METHOD) + &amp;quot;\&amp;quot;&amp;quot;)&lt;br /&gt;
            elif (sc[1] == &amp;quot;olevel&amp;quot;):&lt;br /&gt;
                global OLDSCHOOL_LEVEL&lt;br /&gt;
                host.rcon_invoke(&amp;quot;game.sayAll \&amp;quot;BFO:::      OLDSCHOOL LEVEL: &amp;quot; + str(OLDSCHOOL_LEVEL) + &amp;quot;\&amp;quot;&amp;quot;)&lt;br /&gt;
            elif (sc[1] == &amp;quot;c4&amp;quot;):&lt;br /&gt;
                global NO_C4&lt;br /&gt;
                host.rcon_invoke(&amp;quot;game.sayAll \&amp;quot;BFO:::      NO C4: &amp;quot; + str(NO_C4) + &amp;quot;\&amp;quot;&amp;quot;)&lt;br /&gt;
            elif (sc[1] == &amp;quot;claymore&amp;quot;):&lt;br /&gt;
                global NO_CLAYMORE&lt;br /&gt;
                host.rcon_invoke(&amp;quot;game.sayAll \&amp;quot;BFO:::      NO CLAYMORE: &amp;quot; + str(NO_CLAYMORE) + &amp;quot;\&amp;quot;&amp;quot;)&lt;br /&gt;
            elif (sc[1] == &amp;quot;mgs&amp;quot;):&lt;br /&gt;
                global NO_MOUNTED_MGS&lt;br /&gt;
                host.rcon_invoke(&amp;quot;game.sayAll \&amp;quot;BFO:::      NO MOUNTED MGS: &amp;quot; + str(NO_MOUNTED_MGS) + &amp;quot;\&amp;quot;&amp;quot;)&lt;br /&gt;
            elif (sc[1] == &amp;quot;tow&amp;quot;):&lt;br /&gt;
                global NO_TOW_MISSILE&lt;br /&gt;
                host.rcon_invoke(&amp;quot;game.sayAll \&amp;quot;BFO:::      NO TOW MISSILE: &amp;quot; + str(NO_TOW_MISSILE) + &amp;quot;\&amp;quot;&amp;quot;)&lt;br /&gt;
            elif (sc[1] == &amp;quot;kick_frags&amp;quot;):&lt;br /&gt;
                global HOW_MANY_KILLS_TO_KICK&lt;br /&gt;
                host.rcon_invoke(&amp;quot;game.sayAll \&amp;quot;BFO:::      KICK PLAYER AFTER: &amp;quot; + str(HOW_MANY_KILLS_TO_KICK) + &amp;quot; FRAGS.\&amp;quot;&amp;quot;)&lt;br /&gt;
            elif (sc[1] == &amp;quot;kick_time&amp;quot;):&lt;br /&gt;
                global RESTRICTED_WEAPON_KICK_IN_MINUTES&lt;br /&gt;
                host.rcon_invoke(&amp;quot;game.sayAll \&amp;quot;BFO:::      KICK PLAYER FOR: &amp;quot; + str(RESTRICTED_WEAPON_KICK_IN_MINUTES) + &amp;quot; MIN.\&amp;quot;&amp;quot;)&lt;br /&gt;
            elif (sc[1] == &amp;quot;anticomm&amp;quot;):&lt;br /&gt;
                global ANTICOMMANDER&lt;br /&gt;
                host.rcon_invoke(&amp;quot;game.sayAll \&amp;quot;BFO:::      ANTI COMMANDER: &amp;quot; + str(ANTICOMMANDER) + &amp;quot;\&amp;quot;&amp;quot;)&lt;br /&gt;
            elif (sc[1] == &amp;quot;commkick&amp;quot;):&lt;br /&gt;
                global COMMANDER_AUTOKICK&lt;br /&gt;
                host.rcon_invoke(&amp;quot;game.sayAll \&amp;quot;BFO:::      COMMANDER AUTOKICKER: &amp;quot; + str(COMMANDER_AUTOKICK) + &amp;quot;\&amp;quot;&amp;quot;)&lt;br /&gt;
            elif (sc[1] == &amp;quot;commkick_time&amp;quot;):&lt;br /&gt;
                global COMMANDER_KICK_TIME_IN_MINUTES&lt;br /&gt;
                host.rcon_invoke(&amp;quot;game.sayAll \&amp;quot;BFO:::      KICK COMMANDER FOR: &amp;quot; + str(COMMANDER_KICK_TIME_IN_MINUTES) + &amp;quot; MIN.\&amp;quot;&amp;quot;)&lt;br /&gt;
            elif (sc[1] == &amp;quot;help&amp;quot;):&lt;br /&gt;
                sayAll(&amp;quot;                             Ver 0.9 BETA Last changed: 25.Apr.2008&amp;quot;)&lt;br /&gt;
                sayAll(&amp;quot;                             For more info mail to: misiekbest@misiekbest.pl or visit website: http://bfo.misiekbest.pl&amp;quot;)&lt;br /&gt;
                sayAll(&amp;quot;This help include all commands that can be executed in game console via rcon.&amp;quot;)&lt;br /&gt;
                sayAll(&amp;quot;TO EXECUTE COMMAND TYPE IN CONSOLE: rcon bfo [command] [value].&amp;quot;)&lt;br /&gt;
                sayAll(&amp;quot;&amp;quot;)&lt;br /&gt;
                sayAll(&amp;quot;############## OLDSCHOOL LEVEL ##############&amp;quot;)&lt;br /&gt;
                sayAll(&amp;quot;#############################################&amp;quot;)&lt;br /&gt;
                sayAll(&amp;quot;olevel         # Return number of oldschool level&amp;quot;)&lt;br /&gt;
                sayAll(&amp;quot;olevel [value] # Set oldschool level to given value&amp;quot;)&lt;br /&gt;
                sayAll(&amp;quot;Here are all oldschool levels:&amp;quot;)&lt;br /&gt;
                sayAll(&amp;quot;0 - Scrpit completely disabled.&amp;quot;)&lt;br /&gt;
                sayAll(&amp;quot;1 - ONLY MEDICS and MEDICS UNLOCKS&amp;quot;)&lt;br /&gt;
                sayAll(&amp;quot;2 - ONLY MEDICS and NO MEDICS UNLOCKS&amp;quot;)&lt;br /&gt;
                sayAll(&amp;quot;3 - ONLY KNIFE, PISTOL AND SHOCK PADDLES ALLOWED. NOTE: This level will only work with punish method set to 0 or 2&amp;quot;)&lt;br /&gt;
                sayAll(&amp;quot;4 - NO UNLOCKS&amp;quot;)&lt;br /&gt;
                sayAll(&amp;quot;5 - DONT USE OLDSCHOOL LEVEL, JUST CHECK OTHER THINGS LIKE NO C4 or NO CLAYMORE&amp;quot;)&lt;br /&gt;
                sayAll(&amp;quot;6 - NO SNIPERS&amp;quot;)&lt;br /&gt;
                sayAll(&amp;quot;&amp;quot;)&lt;br /&gt;
                sayAll(&amp;quot;############## PUNISH METHOD  ##############&amp;quot;)&lt;br /&gt;
                sayAll(&amp;quot;############################################&amp;quot;)&lt;br /&gt;
                sayAll(&amp;quot;punish         # Return number of punish method&amp;quot;)&lt;br /&gt;
                sayAll(&amp;quot;punish [value] # Set punish method to given value&amp;quot;)&lt;br /&gt;
                sayAll(&amp;quot;Here are all punish methods:&amp;quot;)&lt;br /&gt;
                sayAll(&amp;quot;0 - Only warning enabled. No other punishment&amp;quot;)&lt;br /&gt;
                sayAll(&amp;quot;1 - Kill player just after respawn with forbidden weapon. If restricted are c4 or claymore player will die after switching to them. This wont work for mounted mgs and tow. Sorry.&amp;quot;)&lt;br /&gt;
                sayAll(&amp;quot;2 - Kick player after previously given kick_frags variable. To set number of frags run: rcon bfo kick_frags [value]&amp;quot;)&lt;br /&gt;
                sayAll(&amp;quot;&amp;quot;)&lt;br /&gt;
                sayAll(&amp;quot;##############   MISC WEAPONS   ##############&amp;quot;)&lt;br /&gt;
                sayAll(&amp;quot;##############################################&amp;quot;)&lt;br /&gt;
                sayAll(&amp;quot;c4         # Return status of C4 restriction&amp;quot;)&lt;br /&gt;
                sayAll(&amp;quot;c4 [value] # Enable or disble C4 restriction. 0-Disable  1-Enable&amp;quot;)&lt;br /&gt;
                sayAll(&amp;quot;claymore         # Return status of CLAYMORE restriction&amp;quot;)&lt;br /&gt;
                sayAll(&amp;quot;claymore [value] # Enable or disble CLAYMORE restriction. 0-Disable  1-Enable&amp;quot;)&lt;br /&gt;
                sayAll(&amp;quot;mgs         # Return status of MOUNTED MGS restriction&amp;quot;)&lt;br /&gt;
                sayAll(&amp;quot;mgs [value] # Enable or disble MOUNTED MGS restriction. 0-Disable  1-Enable&amp;quot;)&lt;br /&gt;
                sayAll(&amp;quot;tow         # Return status of TOW MISSILE restriction&amp;quot;)&lt;br /&gt;
                sayAll(&amp;quot;tow [value] # Enable or disble TOW MISSILE restriction. 0-Disable  1-Enable&amp;quot;)&lt;br /&gt;
                sayAll(&amp;quot;&amp;quot;)&lt;br /&gt;
                sayAll(&amp;quot;##############   KICKER SYSTEM (punish 2)   ##############&amp;quot;)&lt;br /&gt;
                sayAll(&amp;quot;##########################################################&amp;quot;)&lt;br /&gt;
                sayAll(&amp;quot;kick_frags         # Return number of how many kills from restricted weapon to kick player&amp;quot;)&lt;br /&gt;
                sayAll(&amp;quot;kick_frags [value] # Set HOW_MANY_KILLS_TO_KICK to given value&amp;quot;)&lt;br /&gt;
                sayAll(&amp;quot;kick_time          # Return minutes for how long player should be kicked out.&amp;quot;)&lt;br /&gt;
                sayAll(&amp;quot;kick_time [value]  # Set minutes for how long player should be kicked out.&amp;quot;)&lt;br /&gt;
                sayAll(&amp;quot;&amp;quot;)&lt;br /&gt;
                sayAll(&amp;quot;##############    ANTI COMMANDER    ##############&amp;quot;)&lt;br /&gt;
                sayAll(&amp;quot;##################################################&amp;quot;)&lt;br /&gt;
                sayAll(&amp;quot;anticomm           # Return status of ANTICOMMANDER system&amp;quot;)&lt;br /&gt;
                sayAll(&amp;quot;anticomm [value]   # Enable or disble commander restriction. 0-Disable  1-Enable&amp;quot;)&lt;br /&gt;
                sayAll(&amp;quot;commkick           # Return status of COMMANDER KICKER system&amp;quot;)&lt;br /&gt;
                sayAll(&amp;quot;commkick [value]   # Enable or disble commander kicking. 0-Disable  1-Enable&amp;quot;)&lt;br /&gt;
                sayAll(&amp;quot;commkick_time          # Return minutes for how long commander should be kicked out.&amp;quot;)&lt;br /&gt;
                sayAll(&amp;quot;commkick_time [value]  # Set minutes for how long commander should be kicked out.&amp;quot;)&lt;br /&gt;
                sayAll(&amp;quot;&amp;quot;)&lt;br /&gt;
                sayAll(&amp;quot;&amp;quot;)&lt;br /&gt;
                sayAll(&amp;quot;&amp;quot;)&lt;br /&gt;
                sayAll(&amp;quot;&amp;quot;)&lt;br /&gt;
                sayAll(&amp;quot;HELP GENERATED. NOW OPEN YOUR CONSOLE TO SEE IT. YOU CAN NAVIGATE UP AND DOWN BY PRESSING PAGE UP AND PAGE DOWN ON YOUR KEYBOARD&amp;quot;)&lt;br /&gt;
            else:&lt;br /&gt;
                host.rcon_invoke(&amp;quot;game.sayAll \&amp;quot;BFO:::      !!!!ERROR!!!! Unknown command : &amp;quot; + str(sc[1]) + &amp;quot;\&amp;quot;&amp;quot;)&lt;br /&gt;
                host.rcon_invoke(&amp;quot;game.sayAll \&amp;quot;BFO:::      Use: status, punish, olevel, c4, claymore, mgs, tow, kick_frags, kick_time, anticomm, commkick, commkick_time\&amp;quot;&amp;quot;)&lt;br /&gt;
        else:&lt;br /&gt;
            if (isInt(sc[2])):&lt;br /&gt;
                if (sc[1] == &amp;quot;punish&amp;quot;):&lt;br /&gt;
                    if (0&amp;lt;=int(sc[2])&amp;lt;=2):&lt;br /&gt;
                        global PUNISH_METHOD&lt;br /&gt;
                        PUNISH_METHOD = int(sc[2])&lt;br /&gt;
                        if (PUNISH_METHOD == 0 or PUNISH_METHOD == 1):&lt;br /&gt;
                            try:&lt;br /&gt;
                                host.registerHandler(&#039;PlayerChangeWeapon&#039;, onPlayerChangeWeapon, 1)&lt;br /&gt;
                            except:&lt;br /&gt;
                                pass&lt;br /&gt;
                        else:&lt;br /&gt;
                            try:&lt;br /&gt;
                                host.registerHandler(&#039;PlayerKilled&#039;, onPlayerKilled, 1)&lt;br /&gt;
                            except:&lt;br /&gt;
                                pass&lt;br /&gt;
                        host.rcon_invoke(&amp;quot;game.sayAll \&amp;quot;BFO:::      PUNISH METHOD SET TO: &amp;quot; + str(sc[2]) + &amp;quot;\&amp;quot;&amp;quot;)&lt;br /&gt;
                    else:&lt;br /&gt;
                        sayAll(&amp;quot;BFO:::      !!!!ERROR!!!! Punish method must be 0, 1 or 2 &amp;quot;)&lt;br /&gt;
                elif (sc[1] == &amp;quot;olevel&amp;quot;):&lt;br /&gt;
                    if (0&amp;lt;=int(sc[2])&amp;lt;=6):&lt;br /&gt;
                        global OLDSCHOOL_LEVEL&lt;br /&gt;
                        OLDSCHOOL_LEVEL = int(sc[2])&lt;br /&gt;
                        host.rcon_invoke(&amp;quot;game.sayAll \&amp;quot;BFO:::      OLDSCHOOL LEVEL SET TO: &amp;quot; + str(sc[2]) + &amp;quot;\&amp;quot;&amp;quot;)&lt;br /&gt;
                    else:&lt;br /&gt;
                        sayAll(&amp;quot;BFO:::      !!!!ERROR!!!! oldschool level must be 0, 1, 2, 3, 4, 5 or 6&amp;quot;)&lt;br /&gt;
                elif (sc[1] == &amp;quot;c4&amp;quot;):&lt;br /&gt;
                    if (0&amp;lt;=int(sc[2])&amp;lt;=1):&lt;br /&gt;
                        global NO_C4&lt;br /&gt;
                        NO_C4 = int(sc[2])&lt;br /&gt;
                        host.rcon_invoke(&amp;quot;game.sayAll \&amp;quot;BFO:::      NO C4 SET TO: &amp;quot; + str(sc[2]) + &amp;quot;\&amp;quot;&amp;quot;)&lt;br /&gt;
                    else:&lt;br /&gt;
                        sayAll(&amp;quot;BFO:::      !!!!ERROR!!!! C4 can be set only to 0 or 1&amp;quot;)&lt;br /&gt;
                elif (sc[1] == &amp;quot;claymore&amp;quot;):&lt;br /&gt;
                    if (0&amp;lt;=int(sc[2])&amp;lt;=1):&lt;br /&gt;
                        global NO_CLAYMORE&lt;br /&gt;
                        NO_CLAYMORE = int(sc[2])&lt;br /&gt;
                        host.rcon_invoke(&amp;quot;game.sayAll \&amp;quot;BFO:::      NO CLAYMORE SET TO: &amp;quot; + str(sc[2]) + &amp;quot;\&amp;quot;&amp;quot;)&lt;br /&gt;
                    else:&lt;br /&gt;
                        sayAll(&amp;quot;BFO:::      !!!!ERROR!!!! CLAYMORE can be set only to 0 or 1&amp;quot;)&lt;br /&gt;
                elif (sc[1] == &amp;quot;mgs&amp;quot;):&lt;br /&gt;
                    if (0&amp;lt;=int(sc[2])&amp;lt;=1):&lt;br /&gt;
                        global NO_MOUNTED_MGS&lt;br /&gt;
                        NO_MOUNTED_MGS = int(sc[2])&lt;br /&gt;
                        host.rcon_invoke(&amp;quot;game.sayAll \&amp;quot;BFO:::      NO MOUNTED MGS SET TO: &amp;quot; + str(sc[2]) + &amp;quot;\&amp;quot;&amp;quot;)&lt;br /&gt;
                        sayAll(&amp;quot;BFO:::      !!!!ERROR!!!! MGS can be set only to 0 or 1&amp;quot;)&lt;br /&gt;
                elif (sc[1] == &amp;quot;tow&amp;quot;):&lt;br /&gt;
                    if (0&amp;lt;=int(sc[2])&amp;lt;=1):&lt;br /&gt;
                        global NO_TOW_MISSILE&lt;br /&gt;
                        NO_TOW_MISSILE = int(sc[2])&lt;br /&gt;
                        host.rcon_invoke(&amp;quot;game.sayAll \&amp;quot;BFO:::      NO TOW MISSILE SET TO: &amp;quot; + str(sc[2]) + &amp;quot;\&amp;quot;&amp;quot;)&lt;br /&gt;
                    else:&lt;br /&gt;
                        sayAll(&amp;quot;BFO:::      !!!!ERROR!!!! TOW can be set only to 0 or 1&amp;quot;)&lt;br /&gt;
                elif (sc[1] == &amp;quot;kick_frags&amp;quot;):&lt;br /&gt;
                    if (0&amp;lt;=int(sc[2])):&lt;br /&gt;
                        global HOW_MANY_KILLS_TO_KICK&lt;br /&gt;
                        HOW_MANY_KILLS_TO_KICK = int(sc[2])&lt;br /&gt;
                        host.rcon_invoke(&amp;quot;game.sayAll \&amp;quot;BFO:::      HOW MANY KILLS TO KICK SET TO: &amp;quot; + str(sc[2]) + &amp;quot; FRAGS\&amp;quot;&amp;quot;)&lt;br /&gt;
                    else:&lt;br /&gt;
                        sayAll(&amp;quot;BFO:::      !!!!ERROR!!!! KICK_FRAGS must be greater than or equal to 0&amp;quot;)&lt;br /&gt;
                elif (sc[1] == &amp;quot;kick_time&amp;quot;):&lt;br /&gt;
                    if (0&amp;lt;=int(sc[2])):&lt;br /&gt;
                        global RESTRICTED_WEAPON_KICK_IN_MINUTES&lt;br /&gt;
                        RESTRICTED_WEAPON_KICK_IN_MINUTES = int(sc[2])&lt;br /&gt;
                        host.rcon_invoke(&amp;quot;game.sayAll \&amp;quot;BFO:::      KICK PLAYER TIME SET TO: &amp;quot; + str(sc[2]) + &amp;quot; MIN.\&amp;quot;&amp;quot;)&lt;br /&gt;
                    else:&lt;br /&gt;
                        sayAll(&amp;quot;BFO:::      !!!!ERROR!!!! KICK_TIME must be greater than or equal to 0&amp;quot;)&lt;br /&gt;
                elif (sc[1] == &amp;quot;anticomm&amp;quot;):&lt;br /&gt;
                    if (0&amp;lt;=int(sc[2])&amp;lt;=1):&lt;br /&gt;
                        global ANTICOMMANDER&lt;br /&gt;
                        ANTICOMMANDER = int(sc[2])&lt;br /&gt;
                        if (ANTICOMMANDER == 1):&lt;br /&gt;
                            try:&lt;br /&gt;
                                host.registerHandler(&#039;ChangedCommander&#039;, onCommander, 1)&lt;br /&gt;
                            except:&lt;br /&gt;
                                pass&lt;br /&gt;
                        host.rcon_invoke(&amp;quot;game.sayAll \&amp;quot;BFO:::      ANTI COMMANDER SET TO: &amp;quot; + str(sc[2]) + &amp;quot;\&amp;quot;&amp;quot;)&lt;br /&gt;
                    else:&lt;br /&gt;
                        sayAll(&amp;quot;BFO:::      !!!!ERROR!!!! ANTICOMM can be set only to 0 or 1&amp;quot;)&lt;br /&gt;
                elif (sc[1] == &amp;quot;commkick&amp;quot;):&lt;br /&gt;
                    if (0&amp;lt;=int(sc[2])&amp;lt;=1):&lt;br /&gt;
                        global COMMANDER_AUTOKICK&lt;br /&gt;
                        COMMANDER_AUTOKICK = int(sc[2])&lt;br /&gt;
                        host.rcon_invoke(&amp;quot;game.sayAll \&amp;quot;BFO:::      COMMANDER AUTOKICK SET TO: &amp;quot; + str(sc[2]) + &amp;quot;\&amp;quot;&amp;quot;)&lt;br /&gt;
                    else:&lt;br /&gt;
                        sayAll(&amp;quot;BFO:::      !!!!ERROR!!!! COMMKICK can be set only to 0 or 1&amp;quot;)&lt;br /&gt;
                elif (sc[1] == &amp;quot;commkick_time&amp;quot;):&lt;br /&gt;
                    if (0&amp;lt;=int(sc[2])):&lt;br /&gt;
                        global COMMANDER_KICK_TIME_IN_MINUTES&lt;br /&gt;
                        COMMANDER_KICK_TIME_IN_MINUTES = int(sc[2])&lt;br /&gt;
                        host.rcon_invoke(&amp;quot;game.sayAll \&amp;quot;BFO:::      COMMANDER KICK TIME SET TO: &amp;quot; + str(sc[2]) + &amp;quot; MIN.\&amp;quot;&amp;quot;)&lt;br /&gt;
                    else:&lt;br /&gt;
                        sayAll(&amp;quot;BFO:::      !!!!ERROR!!!! COMMKICK_TIME must be greater than or equal to 0&amp;quot;)&lt;br /&gt;
                else:&lt;br /&gt;
                    host.rcon_invoke(&amp;quot;game.sayAll \&amp;quot;BFO:::      !!!!ERROR!!!! Unknown command : &amp;quot; + str(sc[2]) + &amp;quot;\&amp;quot;&amp;quot;)&lt;br /&gt;
                    host.rcon_invoke(&amp;quot;game.sayAll \&amp;quot;BFO:::      Use: punish, olevel, c4, claymore, mgs, tow, kick_frags, kick_time, anticomm, commkick, commkick_time\&amp;quot;&amp;quot;)&lt;br /&gt;
            else:&lt;br /&gt;
                host.rcon_invoke(&amp;quot;game.sayAll \&amp;quot;BFO:::      !!!!ERROR!!!! Third argument must be numerical ammount! You wrote: &amp;quot; + str(sc[2]) + &amp;quot;\&amp;quot;&amp;quot;)&lt;br /&gt;
               &lt;br /&gt;
&lt;br /&gt;
def onGameStatusChange(status):&lt;br /&gt;
    if (status == bf2.GameStatus.EndGame):&lt;br /&gt;
        global playerKickList&lt;br /&gt;
        playerKickList = []&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Pireax</name></author>
	</entry>
	<entry>
		<id>https://bf2tech.uturista.pt/index.php?title=Scripts:ThreatAndWorth&amp;diff=119</id>
		<title>Scripts:ThreatAndWorth</title>
		<link rel="alternate" type="text/html" href="https://bf2tech.uturista.pt/index.php?title=Scripts:ThreatAndWorth&amp;diff=119"/>
		<updated>2018-06-22T15:33:40Z</updated>

		<summary type="html">&lt;p&gt;Pireax: Created page with &amp;quot;__TOC__ == Description  ==  ; Module : &amp;lt;code&amp;gt;ThreatAndWorth.py&amp;lt;/code&amp;gt; ; Author : SHAnders ; Version : 1.01  Server side only admin script or mod addon, you deside the usage!...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
== Description  ==&lt;br /&gt;
&lt;br /&gt;
; Module&lt;br /&gt;
: &amp;lt;code&amp;gt;ThreatAndWorth.py&amp;lt;/code&amp;gt;&lt;br /&gt;
; Author&lt;br /&gt;
: SHAnders&lt;br /&gt;
; Version&lt;br /&gt;
: 1.01&lt;br /&gt;
&lt;br /&gt;
Server side only admin script or mod addon, you deside the usage!&lt;br /&gt;
&lt;br /&gt;
== Features  ==&lt;br /&gt;
&lt;br /&gt;
=== Worth  ===&lt;br /&gt;
&lt;br /&gt;
This script will reward player kills based upon a worth schema. Each players will be assigned a &#039;worth&#039; when they get killed or kill. If victim worth &amp;gt; attacker worth, the attacker is assigned a bonus. Worth is calculated by vehicle, and players position within it plus an addition if player is squadleader or commander, snipers are worth only to other snipers.&lt;br /&gt;
&lt;br /&gt;
=== Threat  ===&lt;br /&gt;
&lt;br /&gt;
This script implements threat rating. The lower the attacker threat raking and the higher the victim threat rating, the higher the bonus and vice versa. Threat rating is based uppon a calculation of a player kills, deaths and scores compared to the average player in the game. Threat rating can be disabled by setting: &amp;lt;code&amp;gt;USE_THREAT_RATING = False&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Survival  ===&lt;br /&gt;
&lt;br /&gt;
At the end of the game players will be rewarded upon their survival rating. The more enemies you kill and the less you get killed, the higher the bonus.&lt;br /&gt;
&lt;br /&gt;
Survivalrating can be disabled by setting : &amp;lt;code&amp;gt;USE_SURVIVAL_RATING = False&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Commander  ===&lt;br /&gt;
&lt;br /&gt;
To please a few people out there it is now possible to disable the commander in this script.&lt;br /&gt;
&lt;br /&gt;
Commander can be disabled by setting: &amp;lt;code&amp;gt;DISABLE_COMMANDER = True&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Installation  ==&lt;br /&gt;
&lt;br /&gt;
Installation as Admin script -- not a mod, adds scoring changes to all games on server:&lt;br /&gt;
&lt;br /&gt;
# Save this script as &amp;lt;code&amp;gt;ThreatAndWorth.py&amp;lt;/code&amp;gt; in your &amp;lt;code&amp;gt;admin/standard_admin&amp;lt;/code&amp;gt; directory.&lt;br /&gt;
# Add the lines &amp;lt;code&amp;gt;import ThreatAndWorth&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;ThreatAndWorth.init()&amp;lt;/code&amp;gt; to the file &amp;lt;code&amp;gt;admin/standard_admin/__init__.py&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Installation as Mod addon -- adds scoring changes only to your mod:&lt;br /&gt;
&lt;br /&gt;
# Save this script as &amp;lt;code&amp;gt;ThreatAndWorth.py&amp;lt;/code&amp;gt; in your &amp;lt;code&amp;gt;mods/&amp;lt;mod_lib&amp;gt;/python/game&amp;lt;/code&amp;gt; directory.&lt;br /&gt;
# Add the lines &amp;lt;code&amp;gt;import ThreatAndWorth&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;ThreatAndWorth.init()&amp;lt;/code&amp;gt; to the file &amp;lt;code&amp;gt;mods/&amp;lt;mod_lib&amp;gt;/python/game/__init__.py&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== TODO:  ==&lt;br /&gt;
&lt;br /&gt;
; Team score&lt;br /&gt;
: Additional points for actions made within 30-50 feet of a commander/squadleader attack/defend/fix/blowup/asembly order&lt;br /&gt;
&lt;br /&gt;
== Thanks To  ==&lt;br /&gt;
&lt;br /&gt;
Battlefield.no for inspiration from their pingkick.py script &lt;br /&gt;
&lt;br /&gt;
== The Code  ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt; &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt; &amp;lt;/code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
 # ------------------------------------------------------------------------&lt;br /&gt;
# Module: ThreatAndWorth.py&lt;br /&gt;
# Author: SHAnders&lt;br /&gt;
#&lt;br /&gt;
# Version 1.01&lt;br /&gt;
# Changes&lt;br /&gt;
# 1.0 -&amp;gt; 1.01&lt;br /&gt;
#    Updated the messagetimer to only start once&lt;br /&gt;
#&lt;br /&gt;
# Description:&lt;br /&gt;
#   Server side only admin script or mod addon, you deside the usage !&lt;br /&gt;
#&lt;br /&gt;
#   This script will reward player kills based uppon a worthschema&lt;br /&gt;
#   Each players will be assigned a &#039;worth&#039; when they get killed or kill&lt;br /&gt;
#   If victim worth &amp;gt; attacker worth, the attacker is assigned a bonus.&lt;br /&gt;
#   Worth is calculated by vehicle, and players position within it plus&lt;br /&gt;
#   an addition if player is squadleader or commander, snipers are worth only to other snipers.&lt;br /&gt;
#&lt;br /&gt;
#   This script implement threat rating. The lower the attacker threat raking&lt;br /&gt;
#   and the higher the victim threat rating, the higher the bonus and vice versa.&lt;br /&gt;
#   Threat rating is based uppon a calculation of a player kills, deaths &amp;amp; scores&lt;br /&gt;
#   compared to the average player in the game.&lt;br /&gt;
#&lt;br /&gt;
#   At the end of the game players will be rewarded uppon their survival rating.&lt;br /&gt;
#   The more enemies you kill and the less you get killed, the higher the bonus.&lt;br /&gt;
#&lt;br /&gt;
#   To please a few people out there it is now posible to disable the commander in this script.&lt;br /&gt;
#&lt;br /&gt;
#   The scoring system provided by ThreatAndWorth refines the idear and system&lt;br /&gt;
#   implemted by the earlier scoringBonuses v1.0&lt;br /&gt;
#   ThreatAndWorth therfor replaces the scoringBonuses script.&lt;br /&gt;
#&lt;br /&gt;
# Requirements:&lt;br /&gt;
#   None.&lt;br /&gt;
#&lt;br /&gt;
# Installation as Admin script -- Not a mod, adds scoring changes to all games on server:&lt;br /&gt;
#   1: Save this script as &#039;ThreatAndWorth.py&#039; in your &amp;lt;bf2&amp;gt;/admin/standard_admin directory.&lt;br /&gt;
#   2: Add the lines &#039;import ThreatAndWorth&#039; and &#039;ThreatAndWorth.init()&#039; to the file&lt;br /&gt;
#      &#039;&amp;lt;bf2&amp;gt;/admin/standard_admin/__init__.py&#039;.&lt;br /&gt;
#&lt;br /&gt;
# Installation as Mod addon -- adds scoring changes only to your mod:&lt;br /&gt;
#   1: Save this script as &#039;ThreatAndWorth.py&#039; in your &amp;lt;bf2&amp;gt;/mods/&amp;lt;mod_lib&amp;gt;/python/game directory.&lt;br /&gt;
#   2: Add the lines &#039;import ThreatAndWorth&#039; and &#039;ThreatAndWorth.init()&#039; to the file&lt;br /&gt;
#      &#039;&amp;lt;bf2&amp;gt;/mods/&amp;lt;mod_lib&amp;gt;/python/game/__init__.py&#039;.&lt;br /&gt;
#&lt;br /&gt;
# TODO:&lt;br /&gt;
#   Team score:&lt;br /&gt;
#     Additional points for actions made within 30-50 feet of a commander/squadleader&lt;br /&gt;
#     attack/defend/fix/blowup/asembly order&lt;br /&gt;
#&lt;br /&gt;
# Thanks to:&lt;br /&gt;
#   Battlefield.no for inspiration from their pingkick.py script&lt;br /&gt;
#&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
import host&lt;br /&gt;
import bf2&lt;br /&gt;
from bf2.stats.constants import *&lt;br /&gt;
from bf2 import g_debug&lt;br /&gt;
from bf2.stats.stats import onGameStatusChanged&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# Constants&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
WORTHSCHEMA = { VEHICLE_TYPE_ARMOR : [ 6, 3, 1, 1, 1, 1, 1, 1 ],&lt;br /&gt;
        VEHICLE_TYPE_AVIATOR : [ 8, 3, 1, 1, 1, 1, 1, 1 ],&lt;br /&gt;
        VEHICLE_TYPE_AIRDEFENSE    : [ 1 ],&lt;br /&gt;
        VEHICLE_TYPE_HELICOPTER    : [ 6, 3, 3, 1, 1, 1, 1, 1 ],&lt;br /&gt;
        VEHICLE_TYPE_TRANSPORT    : [ 3, 3, 1, 1, 1, 1, 1, 1 ],&lt;br /&gt;
        VEHICLE_TYPE_ARTILLERY    : [ 1 ],&lt;br /&gt;
        VEHICLE_TYPE_GRNDDEFENSE : [ 1 ],&lt;br /&gt;
        VEHICLE_TYPE_PARACHUTE : [ 1 ],&lt;br /&gt;
        VEHICLE_TYPE_SOLDIER : [ 0 ] } # index 0 is allways used for victim, 0-7 are all used for attacker&lt;br /&gt;
&lt;br /&gt;
# Aditional worth, only the greatest applies&lt;br /&gt;
VICTIM_SNIPER = 2             # Only applies when attacker is sniper&lt;br /&gt;
VICTIM_SQUADLEADER = 4        # Killing a squadleader in a jet gives good points, But why would he/she be there anyway ... squad members cant spawn there?&lt;br /&gt;
VICTIM_COMMANDER = 6          # Killing a commander in a jet gives good points, But why would he/she be there anyway ... should he/she not bee doing something else?&lt;br /&gt;
&lt;br /&gt;
DEFAULT_VICTIM_WORTH = 1      # Victim will allways be worth this + whats in the WORTHSCHEMA&lt;br /&gt;
USE_THREAT_RATING = True      # Low threat rated players get more points for kills on higher threat rated players [True, False]&lt;br /&gt;
PUBLIC_SCORES = 1             # Score earnings will be made public to the following: [0 = None, 1 = Team, 2 = All]&lt;br /&gt;
USE_SURVIVAL_RATING = True    # At end game players with high survivalrating will be rewarded with (SurvivalRating * (kills - deaths) / restraint) [True, False]&lt;br /&gt;
SURVIVAL_RATING_RESTRAINT = 3 # The higher the number, the lower the bonus (without it the bonus can get very high) [1..*]&lt;br /&gt;
DISABLE_COMMANDER = False     # Not all like the commander, setting this to True will disable this posibility  [True, False]&lt;br /&gt;
&lt;br /&gt;
WELCOME_MSG = &amp;quot;Server is using ThreatAndWorth script v1.0&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# Variables&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
 &lt;br /&gt;
MsgTimer = None # Welcome msg Timer&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# Init&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
def init():&lt;br /&gt;
   host.unregisterGameStatusHandler(onGameStatusChanged) # We need to unregister this to change endscores&lt;br /&gt;
   host.registerGameStatusHandler(onGameStatusChangedThreatAndWorth)&lt;br /&gt;
   host.registerGameStatusHandler(onGameStatusChanged) # We need to register it again after our own handler to make the game work :)&lt;br /&gt;
   MsgTimer = bf2.Timer(onMsgTimer,10,1)&lt;br /&gt;
   if g_debug: print &amp;quot;ThreatAndWort init&amp;quot;&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# onGameStatusChangedThreatAndWorth&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
def onGameStatusChangedThreatAndWorth(status):&lt;br /&gt;
   if status == bf2.GameStatus.Playing:&lt;br /&gt;
      host.registerHandler(&#039;PlayerKilled&#039;, onPlayerKilled)&lt;br /&gt;
      if DISABLE_COMMANDER:&lt;br /&gt;
         host.sh_setEnableCommander(0)&lt;br /&gt;
&lt;br /&gt;
   elif status == bf2.GameStatus.EndGame:&lt;br /&gt;
      if USE_SURVIVAL_RATING:&lt;br /&gt;
         CalculateSurvivalRatingBonus()&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# onPlayerKilled&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
def onPlayerKilled(victim, attacker, weapon, assists, object):&lt;br /&gt;
   victimVehicle = victim.getVehicle()&lt;br /&gt;
  &lt;br /&gt;
   # killed by remote controlled vehicle, no score awarded in this game&lt;br /&gt;
   if victimVehicle and victimVehicle.getIsRemoteControlled():&lt;br /&gt;
      pass&lt;br /&gt;
     &lt;br /&gt;
   # no attacker, killed by object&lt;br /&gt;
   elif attacker == None:&lt;br /&gt;
      pass&lt;br /&gt;
     &lt;br /&gt;
   # killed by self&lt;br /&gt;
   elif attacker == victim:&lt;br /&gt;
      pass&lt;br /&gt;
     &lt;br /&gt;
   # killed by own team&lt;br /&gt;
   elif attacker.getTeam() == victim.getTeam():&lt;br /&gt;
      pass&lt;br /&gt;
&lt;br /&gt;
   # killed by enemy&lt;br /&gt;
   else:&lt;br /&gt;
      CalculateThreatAndWorth(attacker, victim)&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# addBonus&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
def addBonus(player, points):&lt;br /&gt;
   # commander doesnt get bonus for regular actions, only for pure commander tasks.&lt;br /&gt;
   if not player.isCommander():&lt;br /&gt;
      player.score.score += points&lt;br /&gt;
     &lt;br /&gt;
   # commander score&lt;br /&gt;
   commander = bf2.playerManager.getCommander(player.getTeam())&lt;br /&gt;
   if commander != None and commander.isValid() and player != commander and points &amp;gt; 0:&lt;br /&gt;
      preScore = commander.score.score&lt;br /&gt;
      numPlayers = bf2.playerManager.getNumberOfAlivePlayersInTeam(commander.getTeam())&lt;br /&gt;
      if numPlayers &amp;gt; 0:&lt;br /&gt;
         commander.score.score += float(points) / numPlayers&lt;br /&gt;
         scoreGotten = commander.score.score - preScore&lt;br /&gt;
         if scoreGotten &amp;gt; 0:&lt;br /&gt;
            commander.score.cmdScore += scoreGotten&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# Callback function for timer, that delays a message at round start:&lt;br /&gt;
# I hope the fellows at Battlefield.no dont mind me using this !&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
def onMsgTimer(data):&lt;br /&gt;
   global msgtimer&lt;br /&gt;
   sendMsgAll( WELCOME_MSG )&lt;br /&gt;
   msgtimer.destroy()&lt;br /&gt;
   msgtimer = None&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# Send message to all on server&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
def sendMsgAll(msg):&lt;br /&gt;
   host.rcon_invoke(&amp;quot;game.sayAll \&amp;quot;&amp;quot; + str(msg) + &amp;quot;\&amp;quot;&amp;quot;)&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# Send message to all on a team&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
def sendMsgTeam(msg, team):&lt;br /&gt;
   host.rcon_invoke(&amp;quot;game.sayTeam &amp;quot; + str(team) + &amp;quot; \&amp;quot;&amp;quot; + str(msg) + &amp;quot;\&amp;quot;&amp;quot;)&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# Calculate survival endgame points&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
def CalculateSurvivalRatingBonus():&lt;br /&gt;
   playerArgs = bf2.playerManager.getPlayers()&lt;br /&gt;
   for p in playerArgs:&lt;br /&gt;
      survivalRating = GetPlayerSurvivalRating(p)&lt;br /&gt;
      if survivalRating &amp;gt; 0:&lt;br /&gt;
         points = round((p.score.kills - p.score.deaths) * survivalRating / SURVIVAL_RATING_RESTRAINT, 0)&lt;br /&gt;
         addBonus(p, int(points))&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# Get a players survival rating&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
def GetPlayerSurvivalRating( player ):&lt;br /&gt;
   kills = float(player.score.kills + 1)&lt;br /&gt;
   deaths = float(player.score.deaths + 1)&lt;br /&gt;
   survivalRating = kills / deaths&lt;br /&gt;
   return round(survivalRating, 2)&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# Calculate threat and worth points&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
def CalculateThreatAndWorth(attacker, victim):&lt;br /&gt;
   victimVehicle = victim.getVehicle()&lt;br /&gt;
   victimRootVehicle = getRootParent(victimVehicle)&lt;br /&gt;
   attackerVehicle = attacker.getVehicle()&lt;br /&gt;
   attackerRootVehicle = getRootParent(attackerVehicle)&lt;br /&gt;
&lt;br /&gt;
   points = 0&lt;br /&gt;
&lt;br /&gt;
   attackerWorth = GetPlayerWorth( attacker )&lt;br /&gt;
   victimWorth = GetPlayerWorth( victim ) + GetAdditionalVictimWorth(attacker, victim)&lt;br /&gt;
&lt;br /&gt;
   tmpPoints = victimWorth - attackerWorth&lt;br /&gt;
   if tmpPoints &amp;gt; 0:&lt;br /&gt;
      if USE_THREAT_RATING:&lt;br /&gt;
         attackerThreatRating = GetPlayerThreatRating( attacker )&lt;br /&gt;
         victimThreatRating = GetPlayerThreatRating( victim )&lt;br /&gt;
         threatRatingFactor = round((victimThreatRating / attackerThreatRating),3)&lt;br /&gt;
         if threatRatingFactor &amp;lt; 0.125:&lt;br /&gt;
            threatRatingFactor = 0&lt;br /&gt;
         if threatRatingFactor &amp;lt; 0.25:&lt;br /&gt;
            threatRatingFactor = 0.125&lt;br /&gt;
         elif threatRatingFactor &amp;lt; 0.5:&lt;br /&gt;
            threatRatingFactor = 0.25&lt;br /&gt;
         elif threatRatingFactor &amp;lt; 0.75:&lt;br /&gt;
            threatRatingFactor = 0.5&lt;br /&gt;
         elif threatRatingFactor &amp;lt; 1.5:&lt;br /&gt;
            threatRatingFactor = 1&lt;br /&gt;
         elif threatRatingFactor &amp;lt; 2:&lt;br /&gt;
            threatRatingFactor = 1.5&lt;br /&gt;
         else:&lt;br /&gt;
            threatRatingFactor = 2&lt;br /&gt;
         tmpPoints = int(round( threatRatingFactor * tmpPoints,0))&lt;br /&gt;
      points = tmpPoints&lt;br /&gt;
      if points &amp;gt; 0:&lt;br /&gt;
         addBonus(attacker, points)&lt;br /&gt;
         if PUBLIC_SCORES == 2:&lt;br /&gt;
            sendMsgAll( attacker.getName() + &amp;quot; earn points: &amp;quot; + str(points))&lt;br /&gt;
         elif PUBLIC_SCORES == 1:&lt;br /&gt;
            sendMsgTeam( attacker.getName() + &amp;quot; earn points: &amp;quot; + str(points), attacker.getTeam())&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# Calculate additional victim worth&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
def GetAdditionalVictimWorth(attacker, victim):&lt;br /&gt;
   attackerKitType = getKitType(attacker.getKit().templateName)&lt;br /&gt;
   attackerVehicle = attacker.getVehicle()&lt;br /&gt;
   attackerVehicleType = getVehicleType(attackerVehicle.templateName)&lt;br /&gt;
&lt;br /&gt;
   victimKitType = getKitType(victim.getKit().templateName)&lt;br /&gt;
   victimVehicle = victim.getVehicle()&lt;br /&gt;
   victimVehicleType = getVehicleType(victimVehicle.templateName)&lt;br /&gt;
&lt;br /&gt;
   attackerTeamMsg = &amp;quot;&amp;quot;&lt;br /&gt;
   victimTeamMsg = &amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
   worth = DEFAULT_VICTIM_WORTH&lt;br /&gt;
&lt;br /&gt;
   # SNIPER&lt;br /&gt;
   if attackerVehicleType == VEHICLE_TYPE_SOLDIER:&lt;br /&gt;
      if victimVehicleType == VEHICLE_TYPE_SOLDIER:&lt;br /&gt;
         if attackerKitType == KIT_TYPE_SNIPER and victimKitType == KIT_TYPE_SNIPER:&lt;br /&gt;
            worth += VICTIM_SNIPER&lt;br /&gt;
            attackerTeamMsg = attacker.getName() + &amp;quot; has eliminated enemy sniper&amp;quot;&lt;br /&gt;
&lt;br /&gt;
   # SQUADLEADER&lt;br /&gt;
   if victim.isSquadLeader():&lt;br /&gt;
      worth += VICTIM_SQUADLEADER&lt;br /&gt;
      attackerTeamMsg = attacker.getName() + &amp;quot; has eliminated a enemy squadleader &amp;quot; + victim.getName()&lt;br /&gt;
&lt;br /&gt;
   # COMMANDER&lt;br /&gt;
   if victim.isCommander():&lt;br /&gt;
      worth += VICTIM_COMMANDER&lt;br /&gt;
      attackerTeamMsg = attacker.getName() + &amp;quot; has eliminated enemy commander &amp;quot; + victim.getName()&lt;br /&gt;
      victimTeamMsg = &amp;quot;You commander has been eliminated&amp;quot;&lt;br /&gt;
&lt;br /&gt;
   if attackerTeamMsg != &amp;quot;&amp;quot;:&lt;br /&gt;
      sendMsgTeam(attackerTeamMsg, attacker.getTeam())&lt;br /&gt;
&lt;br /&gt;
   if victimTeamMsg != &amp;quot;&amp;quot;:&lt;br /&gt;
      sendMsgTeam(victimTeamMsg, victim.getTeam())&lt;br /&gt;
&lt;br /&gt;
   return worth&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# Calculate a players worth&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
def GetPlayerWorth( player ):&lt;br /&gt;
   worth = -1&lt;br /&gt;
   vehicle = player.getVehicle()&lt;br /&gt;
   rootVehicle = getRootParent(vehicle)&lt;br /&gt;
   vehicleType = getVehicleType(rootVehicle.templateName)&lt;br /&gt;
   args = WORTHSCHEMA[vehicleType]&lt;br /&gt;
   index = GetPlayerIndexInVehicle( player, rootVehicle )&lt;br /&gt;
   if index &amp;gt; -1:&lt;br /&gt;
      worth = args[index]&lt;br /&gt;
   return worth&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# Get a players index inside a vehicle&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
def GetPlayerIndexInVehicle( player, vehicle ):&lt;br /&gt;
   # This dosn&#039;t work on dead player/vehicles ... it allways return 0&lt;br /&gt;
&lt;br /&gt;
   playerArgs = vehicle.getOccupyingPlayers()&lt;br /&gt;
   index = -1&lt;br /&gt;
   found = False&lt;br /&gt;
   while index &amp;lt; len(playerArgs) and not found:&lt;br /&gt;
      index += 1&lt;br /&gt;
      if playerArgs[index] == player:&lt;br /&gt;
         found = True        &lt;br /&gt;
   return index&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# Get a players threat rating&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
def GetPlayerThreatRating( player ):&lt;br /&gt;
   score = 0&lt;br /&gt;
   kills = 0&lt;br /&gt;
   deaths = 0&lt;br /&gt;
   playerArgs = bf2.playerManager.getPlayers()&lt;br /&gt;
   for p in playerArgs:&lt;br /&gt;
      score += p.score.score&lt;br /&gt;
      kills += p.score.kills&lt;br /&gt;
      deaths += p.score.deaths&lt;br /&gt;
&lt;br /&gt;
   avgScore = float(score)/len(playerArgs)&lt;br /&gt;
   avgKills = float(kills)/len(playerArgs)&lt;br /&gt;
   avgDeaths = float(deaths)/len(playerArgs)&lt;br /&gt;
&lt;br /&gt;
   if player.score.score &amp;lt;= 0:&lt;br /&gt;
      scoreFactor = 1/avgScore&lt;br /&gt;
   else:&lt;br /&gt;
      scoreFactor = float(player.score.score)/avgScore&lt;br /&gt;
&lt;br /&gt;
   if player.score.kills &amp;lt;= 0:&lt;br /&gt;
      killsFactor = 1/avgKills&lt;br /&gt;
   else:&lt;br /&gt;
      killsFactor = float(player.score.kills)/avgKills&lt;br /&gt;
&lt;br /&gt;
   if player.score.deaths &amp;lt;= 0:&lt;br /&gt;
      deathsFactor = avgDeaths/1&lt;br /&gt;
   else:&lt;br /&gt;
      deathsFactor = avgDeaths/float(player.score.deaths)&lt;br /&gt;
&lt;br /&gt;
   threatRating = round(killsFactor * deathsFactor * scoreFactor,3)&lt;br /&gt;
&lt;br /&gt;
   return threatRating&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Pireax</name></author>
	</entry>
	<entry>
		<id>https://bf2tech.uturista.pt/index.php?title=Scripts:ClanTkProtection&amp;diff=118</id>
		<title>Scripts:ClanTkProtection</title>
		<link rel="alternate" type="text/html" href="https://bf2tech.uturista.pt/index.php?title=Scripts:ClanTkProtection&amp;diff=118"/>
		<updated>2018-06-22T15:33:18Z</updated>

		<summary type="html">&lt;p&gt;Pireax: Created page with &amp;quot;This script is a modified version of the default tkpunish script.  Clanmembers is a list of current members that will be protected This is the only code changed besides the de...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This script is a modified version of the default tkpunish script.&lt;br /&gt;
&lt;br /&gt;
Clanmembers is a list of current members that will be protected This is the only code changed besides the declare of the list.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
def onPlayerKilled(victim, attacker, weapon, assists, object):&lt;br /&gt;
      &lt;br /&gt;
        string1 = attacker.getName()&lt;br /&gt;
        #Is the attacker protected against punishments? If so, dont handle the event and return&lt;br /&gt;
        for ncount in clanmembers:&lt;br /&gt;
            if string1 == ncount: return&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# tk punish system&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
import bf2&lt;br /&gt;
import host&lt;br /&gt;
from bf2 import g_debug&lt;br /&gt;
&lt;br /&gt;
TK_PUNISH_TIME = 20&lt;br /&gt;
&lt;br /&gt;
TK_PUNISH_COMMANDID = 100&lt;br /&gt;
TK_FORGIVE_COMMANDID = 101&lt;br /&gt;
&lt;br /&gt;
hasPendingTks = {}&lt;br /&gt;
updateTimer = None&lt;br /&gt;
&lt;br /&gt;
clanmembers = [&amp;quot;|TAG|Bill&amp;quot;,&amp;quot;|TAG|John&amp;quot;,&amp;quot;|TAG|Blue&amp;quot;]#clan members to protect&lt;br /&gt;
&lt;br /&gt;
class TkData:&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        self.punished = 0&lt;br /&gt;
        self.pending = []&lt;br /&gt;
        self.lastTKedBy = None&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def init():&lt;br /&gt;
    if g_debug: print &amp;quot;initializing tk-punish script&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    host.registerHandler(&#039;PlayerConnect&#039;, onPlayerConnect, 1)&lt;br /&gt;
    host.registerHandler(&#039;PlayerKilled&#039;, onPlayerKilled)&lt;br /&gt;
    host.registerHandler(&#039;ClientCommand&#039;, onClientCommand)&lt;br /&gt;
&lt;br /&gt;
    # Connect already connected players if reinitializing&lt;br /&gt;
    for p in bf2.playerManager.getPlayers():&lt;br /&gt;
        onPlayerConnect(p)&lt;br /&gt;
   &lt;br /&gt;
    checkEnable()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def checkEnable():&lt;br /&gt;
    global updateTimer&lt;br /&gt;
   &lt;br /&gt;
    if not bf2.serverSettings.getTKPunishEnabled():&lt;br /&gt;
        if updateTimer:&lt;br /&gt;
            updateTimer.destroy()&lt;br /&gt;
            updateTimer = None&lt;br /&gt;
        return False&lt;br /&gt;
    else:&lt;br /&gt;
        if not updateTimer:&lt;br /&gt;
            #if g_debug: print &amp;quot;Started timer&amp;quot;&lt;br /&gt;
            updateTimer = bf2.Timer(onUpdate, 10, 1)&lt;br /&gt;
            updateTimer.setRecurring(10)&lt;br /&gt;
           &lt;br /&gt;
        return True&lt;br /&gt;
   &lt;br /&gt;
&lt;br /&gt;
def onUpdate(data):&lt;br /&gt;
    if not checkEnable(): return&lt;br /&gt;
    global hasPendingTks&lt;br /&gt;
&lt;br /&gt;
    #if len(hasPendingTks) &amp;gt; 0:&lt;br /&gt;
    #    if g_debug: print &amp;quot;update: Has pending tks!&amp;quot;&lt;br /&gt;
    #else:&lt;br /&gt;
    #    if g_debug: print &amp;quot;update:No pending tks.&amp;quot;&lt;br /&gt;
       &lt;br /&gt;
&lt;br /&gt;
    currentTime = host.timer_getWallTime()&lt;br /&gt;
&lt;br /&gt;
    newPending = {}&lt;br /&gt;
    for attacker in hasPendingTks.iterkeys():&lt;br /&gt;
        newList = []&lt;br /&gt;
        #if g_debug: print &amp;quot;attacker pending list:&amp;quot;, len(attacker.tkData.pending)&lt;br /&gt;
        for tk in attacker.tkData.pending:&lt;br /&gt;
            tkDate = tk[0]&lt;br /&gt;
            tkVictim = tk[1]&lt;br /&gt;
            #if g_debug: print &amp;quot;check %d %s&amp;quot; % (tkDate, tkVictim.getName())&lt;br /&gt;
&lt;br /&gt;
            # if there is a pending TK with time expired&lt;br /&gt;
            if tkDate + TK_PUNISH_TIME &amp;lt; currentTime:&lt;br /&gt;
                if bf2.serverSettings.getTKPunishByDefault():&lt;br /&gt;
                    attacker.tkData.punished += 1&lt;br /&gt;
                    checkPunishLimit(attacker)&lt;br /&gt;
                #    if g_debug: print &amp;quot;Default punished &amp;quot;, attacker.getName()&lt;br /&gt;
                else:&lt;br /&gt;
                #    if g_debug: print &amp;quot;Timeouted pending tk for &amp;quot;, attacker.getName()&lt;br /&gt;
                    pass&lt;br /&gt;
&lt;br /&gt;
                # remove player from global list, if it was the last tk&lt;br /&gt;
                if len(attacker.tkData.pending) == 1:&lt;br /&gt;
                    pass&lt;br /&gt;
                else:&lt;br /&gt;
                    newPending[attacker] = 1&lt;br /&gt;
           &lt;br /&gt;
            else:&lt;br /&gt;
                newList += [tk]&lt;br /&gt;
                newPending[attacker] = 1&lt;br /&gt;
       &lt;br /&gt;
        attacker.tkData.pending = newList&lt;br /&gt;
&lt;br /&gt;
    hasPendingTks = newPending&lt;br /&gt;
   &lt;br /&gt;
                       &lt;br /&gt;
def checkPunishLimit(player):&lt;br /&gt;
    #if g_debug: print &amp;quot;player %s has %d punishes&amp;quot; % (player.getName(), player.tkData.punished)&lt;br /&gt;
&lt;br /&gt;
    if player.tkData.punished &amp;gt;= bf2.serverSettings.getTKNumPunishToKick():&lt;br /&gt;
        if g_debug: print &amp;quot;%s reached punish limit&amp;quot; % player.getName()&lt;br /&gt;
        if g_debug: print &amp;quot;Banning player!&amp;quot;&lt;br /&gt;
       &lt;br /&gt;
        result = host.rcon_invoke(&amp;quot;admin.banPlayer &amp;quot; + str(player.index) + &amp;quot; Round&amp;quot;)&lt;br /&gt;
       &lt;br /&gt;
   &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# event actions   &lt;br /&gt;
&lt;br /&gt;
def onPlayerConnect(player):&lt;br /&gt;
    player.tkData = TkData()&lt;br /&gt;
&lt;br /&gt;
def onClientCommand(command, issuer, args):&lt;br /&gt;
    if not checkEnable(): return&lt;br /&gt;
   &lt;br /&gt;
    #if g_debug: print &amp;quot;received client command&amp;quot;&lt;br /&gt;
    if command == TK_PUNISH_COMMANDID:&lt;br /&gt;
        executePunishAction(issuer, True)&lt;br /&gt;
    elif command == TK_FORGIVE_COMMANDID:&lt;br /&gt;
        executePunishAction(issuer, False)&lt;br /&gt;
       &lt;br /&gt;
&lt;br /&gt;
def onPlayerKilled(victim, attacker, weapon, assists, object):&lt;br /&gt;
      &lt;br /&gt;
        string1 = attacker.getName()&lt;br /&gt;
        #Is the attacker protected against punishments? If so, dont handle the event and return&lt;br /&gt;
        for ncount in clanmembers:&lt;br /&gt;
            if string1 == ncount: return&lt;br /&gt;
       &lt;br /&gt;
    if not checkEnable(): return&lt;br /&gt;
&lt;br /&gt;
    if not victim or not attacker or victim == attacker or victim.getTeam() != attacker.getTeam(): return&lt;br /&gt;
   &lt;br /&gt;
    # ok, we have a teamkill&lt;br /&gt;
   &lt;br /&gt;
    currentTime = host.timer_getWallTime()&lt;br /&gt;
    attacker.tkData.pending += [(currentTime, victim)]&lt;br /&gt;
    hasPendingTks[attacker] = 1&lt;br /&gt;
       &lt;br /&gt;
    victim.tkData.lastTKedBy = attacker # can only punish / forgive the last TK&#039;er&lt;br /&gt;
   &lt;br /&gt;
    bf2.gameLogic.sendClientCommand(victim.index, 100, (2, victim.index, attacker.index, TK_PUNISH_TIME))&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def executePunishAction(victim, punish):&lt;br /&gt;
    if not checkEnable() or not victim or not victim.isValid(): return&lt;br /&gt;
    attacker = victim.tkData.lastTKedBy&lt;br /&gt;
    if attacker == None or not attacker.isValid(): return&lt;br /&gt;
&lt;br /&gt;
    global hasPendingTks&lt;br /&gt;
&lt;br /&gt;
    if punish:&lt;br /&gt;
        if g_debug: print &amp;quot;%s tkPunished %s&amp;quot; % (victim.getName(), attacker.getName())&lt;br /&gt;
    else:&lt;br /&gt;
        if g_debug: print &amp;quot;%s tkForgive %s&amp;quot; % (victim.getName(), attacker.getName())&lt;br /&gt;
&lt;br /&gt;
    currentTime = host.timer_getWallTime()&lt;br /&gt;
   &lt;br /&gt;
    newList = []&lt;br /&gt;
    for tk in attacker.tkData.pending:&lt;br /&gt;
        tkDate = tk[0]&lt;br /&gt;
        tkVictim = tk[1]&lt;br /&gt;
       &lt;br /&gt;
        # if the attacker had a pending tk, and time has not run out&lt;br /&gt;
        if tkVictim == victim and tkDate + TK_PUNISH_TIME &amp;gt; currentTime:&lt;br /&gt;
            if punish:&lt;br /&gt;
                attacker.tkData.punished += 1&lt;br /&gt;
                bf2.gameLogic.sendClientCommand(-1, 100, (0, victim.index, attacker.index)) # 100 = tkpunish event, 0 = punish&lt;br /&gt;
                if g_debug: print &amp;quot;%s punished %s, now has %d punishes&amp;quot; % (victim.getName(), attacker.getName(), attacker.tkData.punished)&lt;br /&gt;
            else:&lt;br /&gt;
                bf2.gameLogic.sendClientCommand(-1, 100, (1, victim.index, attacker.index)) # 100 = tkpunish event, 1 = forgive&lt;br /&gt;
                if g_debug: print &amp;quot;%s forgave %s&amp;quot; % (victim.getName(), attacker.getName())&lt;br /&gt;
        else:&lt;br /&gt;
            newList += [tk]&lt;br /&gt;
           &lt;br /&gt;
    attacker.tkData.pending = newList&lt;br /&gt;
   &lt;br /&gt;
    if len(attacker.tkData.pending) == 0:&lt;br /&gt;
        del hasPendingTks[attacker]&lt;br /&gt;
   &lt;br /&gt;
    checkPunishLimit(attacker)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Pireax</name></author>
	</entry>
	<entry>
		<id>https://bf2tech.uturista.pt/index.php?title=Scripts:OfftimePy&amp;diff=117</id>
		<title>Scripts:OfftimePy</title>
		<link rel="alternate" type="text/html" href="https://bf2tech.uturista.pt/index.php?title=Scripts:OfftimePy&amp;diff=117"/>
		<updated>2018-06-22T15:32:58Z</updated>

		<summary type="html">&lt;p&gt;Pireax: Created page with &amp;quot;__TOC__ == What It Does  ==  Allows you to have specific settings for when the number of players is below or equal to and above &amp;lt;code&amp;gt;sv.numPlayersNeededToStart&amp;lt;/code&amp;gt;. For in...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
== What It Does  ==&lt;br /&gt;
&lt;br /&gt;
Allows you to have specific settings for when the number of players is below or equal to and above &amp;lt;code&amp;gt;sv.numPlayersNeededToStart&amp;lt;/code&amp;gt;. For instance you can turn friendly-fire off and have instant spawn time when there aren&#039;t enough players to start a game.&lt;br /&gt;
&lt;br /&gt;
== Installation  ==&lt;br /&gt;
&lt;br /&gt;
# Browse to &amp;lt;code&amp;gt;admin/standard_admin&amp;lt;/code&amp;gt; in your bf2 server directory&lt;br /&gt;
# Edit &amp;lt;code&amp;gt;__init__.py&amp;lt;/code&amp;gt; so it looks something like the code snippet below.&lt;br /&gt;
# Save the below code to &amp;lt;code&amp;gt;admin/standard_admin/offtime.py&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Make sure RCON is configured, then run your server. If &amp;quot;&amp;lt;code&amp;gt;offtime.py loaded&amp;lt;/code&amp;gt;&amp;quot; comes up in your server console it should work from there.&lt;br /&gt;
&lt;br /&gt;
== Usage  ==&lt;br /&gt;
&lt;br /&gt;
Edit the two dictionaries and add the settings you&#039;d like each for each game state. The keys should be strings that represent &amp;lt;code&amp;gt;sv&amp;lt;/code&amp;gt; settings and the values should be strings.&lt;br /&gt;
&lt;br /&gt;
== Code  ==&lt;br /&gt;
&lt;br /&gt;
=== __init__.py  ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
import offtime&lt;br /&gt;
&lt;br /&gt;
offtime.init()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== offtime.py  ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# offtime.py - allows different settings for both&lt;br /&gt;
# sv.numPlayersNeededToStart-related game states&lt;br /&gt;
# -- by dackz (http://dackz.net/)&lt;br /&gt;
import bf2&lt;br /&gt;
import host&lt;br /&gt;
from bf2 import g_debug&lt;br /&gt;
&lt;br /&gt;
# change these to reflect the settings you want&lt;br /&gt;
settingsNotStarted = {&lt;br /&gt;
    &#039;sv.soldierFriendlyFire&#039;: &#039;0&#039;,&lt;br /&gt;
    &#039;sv.soldierSplashFriendlyFire&#039;: &#039;0&#039;,&lt;br /&gt;
    &#039;sv.vehicleFriendlyFire&#039;: &#039;0&#039;,&lt;br /&gt;
    &#039;sv.vehicleSplashFriendlyFire&#039;: &#039;0&#039;,&lt;br /&gt;
    &#039;sv.spawnTime&#039;: &#039;0&#039;,&lt;br /&gt;
    &#039;sv.manDownTime&#039;: &#039;0&#039;,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
settingsStarted = {&lt;br /&gt;
    &#039;sv.soldierFriendlyFire&#039;: &#039;25&#039;,&lt;br /&gt;
    &#039;sv.soldierSplashFriendlyFire&#039;: &#039;25&#039;,&lt;br /&gt;
    &#039;sv.vehicleFriendlyFire&#039;: &#039;25&#039;,&lt;br /&gt;
    &#039;sv.vehicleSplashFriendlyFire&#039;: &#039;25&#039;,&lt;br /&gt;
    &#039;sv.spawnTime&#039;: &#039;13&#039;,&lt;br /&gt;
    &#039;sv.manDownTime&#039;: &#039;13&#039;,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
def init():&lt;br /&gt;
    if g_debug: print &#039;initialising offtime script&#039;&lt;br /&gt;
&lt;br /&gt;
    host.registerGameStatusHandler(onGameStatusChanged)&lt;br /&gt;
&lt;br /&gt;
    host.rcon_invoke(&#039;echo &amp;quot;offtime.py loaded&amp;quot;&#039;)&lt;br /&gt;
&lt;br /&gt;
def onGameStatusChanged(status):&lt;br /&gt;
    if status == bf2.GameStatus.Playing:&lt;br /&gt;
        if bf2.playerManager.getNumberOfPlayers() &amp;lt; int(host.rcon_invoke(&#039;sv.numPlayersNeededToStart&#039;)):&lt;br /&gt;
            host.rcon_invoke(&#039;echo &amp;quot;offtime.py: setting offtime setings&amp;quot;&#039;)&lt;br /&gt;
            dictionary = settingsNotStarted&lt;br /&gt;
        else:&lt;br /&gt;
            host.rcon_invoke(&#039;echo &amp;quot;offtime.py: setting normal settings&amp;quot;&#039;)&lt;br /&gt;
            dictionary = settingsStarted&lt;br /&gt;
&lt;br /&gt;
        for (setting, value) in dictionary.iteritems():&lt;br /&gt;
            host.rcon_invoke(&#039;%s %s&#039; % (setting, value))&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Pireax</name></author>
	</entry>
	<entry>
		<id>https://bf2tech.uturista.pt/index.php?title=Scripts:MM_MapAutoSizer&amp;diff=116</id>
		<title>Scripts:MM MapAutoSizer</title>
		<link rel="alternate" type="text/html" href="https://bf2tech.uturista.pt/index.php?title=Scripts:MM_MapAutoSizer&amp;diff=116"/>
		<updated>2018-06-22T15:32:09Z</updated>

		<summary type="html">&lt;p&gt;Pireax: Created page with &amp;quot;__TOC__ == Introduction  ==  After trying out Scripts:AutoMap and finding that it didn&amp;#039;t do exactly what I wanted (and didn&amp;#039;t seem to work with BF2 1.12),...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
== Introduction  ==&lt;br /&gt;
&lt;br /&gt;
After trying out [[Scripts:AutoMap|Scripts:AutoMap]] and finding that it didn&#039;t do exactly what I wanted (and didn&#039;t seem to work with BF2 1.12), I decided to write a plugin for the popular [[ModManager|ModManager]] package that comes with [http://www.bf2cc.com/ BF2CC]. The idea is based on [[Scripts:AutoMap|Scripts:AutoMap]], but there are some important differences:&lt;br /&gt;
&lt;br /&gt;
* no randomizer&lt;br /&gt;
* the map rotation is read directly out of the BF2 server and not from maplist.con. This allows you to use this script even when you&#039;re changing your map rotation on the fly, without messing things up. It also allows map voting to work properly.&lt;br /&gt;
* map size thresholds are configurable through the modmanager configuration file&lt;br /&gt;
&lt;br /&gt;
== Downloading  ==&lt;br /&gt;
&lt;br /&gt;
You can always find the most current version at the [http://www.gloryhoundz.com/code/ GloryHoundz Code Repository]. As of this writing, the latest version is 1.0 to be found here: [http://www.gloryhoundz.com/code/mm_mapautosizer/1.0/mm_mapautosizer.py mm_mapautosizer.py].&lt;br /&gt;
&lt;br /&gt;
== Prerequisites  ==&lt;br /&gt;
&lt;br /&gt;
[[ModManager|ModManager]] or [http://www.bf2cc.com/ BF2CC] &lt;br /&gt;
&lt;br /&gt;
== Install  ==&lt;br /&gt;
&lt;br /&gt;
* copy the file to &#039;&#039;admin/modules&#039;&#039; in your Battlefield 2 server install.&lt;br /&gt;
* change your &#039;&#039;modmanager.con&#039;&#039; and include the following line:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&#039;&#039;modmanager.loadModule &amp;quot;mm_mapautosizer&amp;quot;&#039;&#039;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* The default threshold for 32-size maps is 16 players and for 64-size maps it&#039;s 32 players. You can set your own thresholds by adding two configuration lines to &#039;&#039;modmanager.con&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&#039;&#039;mm_mapautosizer.threshold_64 40&#039;&#039;&lt;br /&gt;
&#039;&#039;mm_mapautosizer.threshold_32 20&#039;&#039;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Bugs/Comments  ==&lt;br /&gt;
&lt;br /&gt;
If you encounter any problems, stop by the [http://www.gloryhoundz.com/forums/ GloryHoundz Forums] and post about it. &lt;br /&gt;
&lt;br /&gt;
== The Code ==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# vim: ts=4 sw=4 noexpandtab&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;MapAutoSizer module&lt;br /&gt;
&lt;br /&gt;
===== About =====&lt;br /&gt;
 This ModManager script was created by GloryHoundz.com to allow for auto&lt;br /&gt;
 sizing of maps in rotation based on the number of people on a server.&lt;br /&gt;
&lt;br /&gt;
 Inspired and partially based on the DontCamp.com dc_automap.py script from&lt;br /&gt;
 http://bf2.fun-o-matic.org/index.php/Scripts:AutoMap&lt;br /&gt;
&lt;br /&gt;
===== Config =====&lt;br /&gt;
 # 64 Player map threshold. End of map number of players to trigger 64-size map&lt;br /&gt;
 mm_mapautosizer.threshold_64 32&lt;br /&gt;
&lt;br /&gt;
 # 32 Player map threshold. End of map number of players to trigger 32-size map&lt;br /&gt;
 mm_mapautosizer.threshold_32 16&lt;br /&gt;
&lt;br /&gt;
===== History =====&lt;br /&gt;
 v1.0 - 1/15/2006:&lt;br /&gt;
 Initial public release: fixed map voting support&lt;br /&gt;
&lt;br /&gt;
 v0.9 - 1/08/2006:&lt;br /&gt;
 Internal GloryHoundz.com release&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
import bf2&lt;br /&gt;
import host&lt;br /&gt;
import mm_utils&lt;br /&gt;
import re&lt;br /&gt;
&lt;br /&gt;
# Set the version of your module here&lt;br /&gt;
__version__ = 1.0&lt;br /&gt;
&lt;br /&gt;
# Set the required module versions here&lt;br /&gt;
__required_modules__ = {&lt;br /&gt;
    &#039;modmanager&#039;: 1.0&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
# Does this module support reload ( are all its reference closed on shutdown? )&lt;br /&gt;
__supports_reload__ = True&lt;br /&gt;
&lt;br /&gt;
# Set the description of your module here&lt;br /&gt;
__description__ = &amp;quot;MapAutoSizer v%s&amp;quot; % __version__&lt;br /&gt;
&lt;br /&gt;
# Add all your configuration options here&lt;br /&gt;
configDefaults = {&lt;br /&gt;
    &#039;threshold_64&#039;: 32,&lt;br /&gt;
    &#039;threshold_32&#039;: 16&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
class MapAutoSizer( object ):&lt;br /&gt;
&lt;br /&gt;
    def __init__( self, modManager ):&lt;br /&gt;
        # ModManager reference&lt;br /&gt;
        self.mm = modManager&lt;br /&gt;
&lt;br /&gt;
        # Internal shutdown state&lt;br /&gt;
        self.__state = 0&lt;br /&gt;
&lt;br /&gt;
        # Add any static initialisation here.&lt;br /&gt;
        # Note: Handler registration should not be done here&lt;br /&gt;
        # but instead in the init() method&lt;br /&gt;
&lt;br /&gt;
    def onGameStatusChanged(self, status):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Control Map rotation.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
        threshold64 = self.__config[&#039;threshold_64&#039;]&lt;br /&gt;
        threshold32 = self.__config[&#039;threshold_32&#039;]&lt;br /&gt;
        if 1 != self.__state:&lt;br /&gt;
            return 0&lt;br /&gt;
&lt;br /&gt;
        if status == bf2.GameStatus.EndGame:&lt;br /&gt;
            host.rcon_invoke(&#039;echo &amp;quot;MapAutoSizer Initializing&amp;quot;&#039;)&lt;br /&gt;
&lt;br /&gt;
            rawMapRotation = host.rcon_invoke(&#039;maplist.list&#039;).split(&amp;quot;\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
            mapRotation = []&lt;br /&gt;
            for mapLine in rawMapRotation:&lt;br /&gt;
                if mapLine:&lt;br /&gt;
                    mapParts = mapLine.split(&amp;quot; &amp;quot;)&lt;br /&gt;
                    if mapParts[1]:&lt;br /&gt;
                        mapRotation.append(mapParts[1])&lt;br /&gt;
&lt;br /&gt;
            nextMapIndex = int(host.rcon_invoke(&#039;admin.nextLevel&#039;))&lt;br /&gt;
            if nextMapIndex &amp;gt;= len(mapRotation):&lt;br /&gt;
                nextMapIndex = 0&lt;br /&gt;
            host.rcon_invoke(&#039;echo &amp;quot;MapAutoSizer next map index: %s&amp;quot;&#039; % (nextMapIndex))&lt;br /&gt;
&lt;br /&gt;
            nextMap = mapRotation[nextMapIndex]&lt;br /&gt;
            host.rcon_invoke(&#039;echo &amp;quot;MapAutoSizer next map: %s&amp;quot;&#039; % (nextMap))&lt;br /&gt;
&lt;br /&gt;
            numPlayers = 0&lt;br /&gt;
&lt;br /&gt;
            for p in bf2.playerManager.getPlayers():&lt;br /&gt;
                numPlayers += 1&lt;br /&gt;
&lt;br /&gt;
            host.rcon_invoke(&#039;echo &amp;quot;MapAutoSizer number of players: %s&amp;quot;&#039; % (numPlayers))&lt;br /&gt;
&lt;br /&gt;
            if numPlayers &amp;gt;= threshold64:&lt;br /&gt;
                mapSize = 64&lt;br /&gt;
            if numPlayers &amp;lt; threshold64:&lt;br /&gt;
                mapSize = 32&lt;br /&gt;
            if numPlayers &amp;lt; threshold32:&lt;br /&gt;
                mapSize = 16&lt;br /&gt;
&lt;br /&gt;
            host.rcon_invoke(&#039;echo &amp;quot;Changing map entry (index,name,size): (%s,%s,%s)&amp;quot;&#039; % (nextMapIndex, nextMap, mapSize))&lt;br /&gt;
            host.rcon_invoke(&#039;maplist.insert %s %s gpm_cq %d&#039; % (nextMapIndex, nextMap, mapSize))&lt;br /&gt;
            host.rcon_invoke(&#039;maplist.remove %s&#039; % (nextMapIndex+1))&lt;br /&gt;
            host.rcon_invoke(&#039;admin.setnextlevel %s&#039; % (nextMapIndex))&lt;br /&gt;
            host.rcon_invoke(&#039;echo &amp;quot;MapAutoSizer finished&amp;quot;&#039;)&lt;br /&gt;
&lt;br /&gt;
    def init( self ):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Provides default initialisation.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
        # Load the configuration&lt;br /&gt;
        self.__config = self.mm.getModuleConfig( configDefaults )&lt;br /&gt;
&lt;br /&gt;
        if 0 == self.__state:&lt;br /&gt;
            # Register GameStatus event handler&lt;br /&gt;
            host.registerGameStatusHandler(self.onGameStatusChanged)&lt;br /&gt;
&lt;br /&gt;
        # Update to the running state&lt;br /&gt;
        self.__state = 1&lt;br /&gt;
&lt;br /&gt;
    def shutdown( self ):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Shutdown and stop processing.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
        # Flag as shutdown as there is currently way to:&lt;br /&gt;
        # host.unregisterHandler&lt;br /&gt;
        self.__state = 2&lt;br /&gt;
&lt;br /&gt;
        # Unregister GameStatus event handler&lt;br /&gt;
        host.unregisterGameStatusHandler(self.onGameStatusChanged)&lt;br /&gt;
&lt;br /&gt;
    def update( self ):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Process and update.&lt;br /&gt;
        Note: This is called VERY often processing in here should&lt;br /&gt;
        be kept to an absolute minimum.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        pass&lt;br /&gt;
&lt;br /&gt;
def mm_load( modManager ):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Creates and returns the MapAutoSizer object.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    return MapAutoSizer( modManager )&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Changelog  ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
v1.0 - 1/15/2006:&lt;br /&gt;
Initial public release: fixed map voting support&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
v0.9 - 1/08/2006:&lt;br /&gt;
Internal GloryHoundz.com release&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Pireax</name></author>
	</entry>
	<entry>
		<id>https://bf2tech.uturista.pt/index.php?title=Scripts:SquadlessKick&amp;diff=115</id>
		<title>Scripts:SquadlessKick</title>
		<link rel="alternate" type="text/html" href="https://bf2tech.uturista.pt/index.php?title=Scripts:SquadlessKick&amp;diff=115"/>
		<updated>2018-06-22T15:31:51Z</updated>

		<summary type="html">&lt;p&gt;Pireax: Created page with &amp;quot;__TOC__ == Introduction  ==  In an effort to learn Python and create something useful, I wrote this script to kick squadless players. It&amp;#039;s a step towards a smoothly running te...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
== Introduction  ==&lt;br /&gt;
&lt;br /&gt;
In an effort to learn Python and create something useful, I wrote this script to kick squadless players. It&#039;s a step towards a smoothly running team. &lt;br /&gt;
&lt;br /&gt;
== The Algorithm  ==&lt;br /&gt;
&lt;br /&gt;
Originally, the script performed a check when players died. However, this caused problems with the autobalancing system because the way BF2 triggers events when switching teams. When a player switches teams, he is removed from a squad (if it applies), killed, and switched to the other side. The problem with checking at player death is the autobalance triggers it when switching a player to another team. Of course, he will definitely not be in a squad and be kicked.&lt;br /&gt;
&lt;br /&gt;
A better way of performing the check is on player spawn. This ensures the intention of whether the player wants to work in a squad or not. Combined with Python&#039;s ability to use lists as queues, squadless players can be processed at a specified interval after they spawn squadless.&lt;br /&gt;
&lt;br /&gt;
When the player spawns, we want to perform the check and add the player to the queue if he is squadless. Setting a timer will perform a second check at a specified period after the player spawns.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Player spawns&lt;br /&gt;
    Player is not in a squad or not commanding&lt;br /&gt;
        Player is added to a kick list&lt;br /&gt;
        Player is issued a warning to join a squad&lt;br /&gt;
        Set timer to kick player&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When the kick timer is triggered, we want to double-check that the player is still squadless. It&#039;s like a second chance. What we do is get the first player in the list and perform the check on him. This would be at the specified time after the player has spawned.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Kick timer is triggered&lt;br /&gt;
    Retrieve first player in kick list&lt;br /&gt;
    Player is not in a squad or not commanding&lt;br /&gt;
        Player is kicked from server&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We want to be fair and issue a general warning to all players every so often so they know to join a squad. If this timer is set to half the time of the kick timer, we can be sure that squadless players will see the warning at least once.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Message timer is triggered&lt;br /&gt;
    Display message to all players&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In between games, we want to clean up the message timer and clear the kick list. Everybody starts fresh on a new round!&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Game status changes&lt;br /&gt;
    Game status is Playing&lt;br /&gt;
        Set the message timer to trigger at set interval&lt;br /&gt;
    Game status is PreGame&lt;br /&gt;
        Destroy message timer&lt;br /&gt;
        Clear the kick list&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
  &lt;br /&gt;
== Code  ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Squadless Kick System&lt;br /&gt;
&lt;br /&gt;
# Module: squadless_kick_v2.py&lt;br /&gt;
# Author: Sarc&lt;br /&gt;
# Version: 0.3a&lt;br /&gt;
# Description: Players not in a squad will be kicked from the server.&lt;br /&gt;
#            An automated message will issue general warnings at specified intervals.&lt;br /&gt;
#            Squadless player checks are done when the player spawns.&lt;br /&gt;
&lt;br /&gt;
# Installation:&lt;br /&gt;
#    Save this script, &#039;squadless_kick_v2.py&#039;, in your &amp;lt;bf2&amp;gt;/admin/standard_admin directory.&lt;br /&gt;
#    Add &#039;import squadless_kick_v2&#039; and &#039;squadless_kick_v2.init()&#039; to the file &#039;&amp;lt;bf2&amp;gt;/admin/standard_admin/__init__.py&#039;.&lt;br /&gt;
&lt;br /&gt;
import bf2&lt;br /&gt;
import host&lt;br /&gt;
from bf2 import g_debug&lt;br /&gt;
&lt;br /&gt;
#debug flag&lt;br /&gt;
sks_debug = False # for verbose server console messages&lt;br /&gt;
&lt;br /&gt;
#variable settings; intervals are in seconds&lt;br /&gt;
kickInterval = 60 # time before a squadless player is kicked&lt;br /&gt;
msgInterval = 30 # time between warning messages&lt;br /&gt;
warningMsg = &amp;quot;ADMIN: |c1000Squadless players will be kicked!&amp;quot; # the warning message&lt;br /&gt;
&lt;br /&gt;
#timers&lt;br /&gt;
msgTimer = None&lt;br /&gt;
&lt;br /&gt;
#queue lists&lt;br /&gt;
kickList = []&lt;br /&gt;
&lt;br /&gt;
# Initialize the kick system i.e. register game hooks.&lt;br /&gt;
def init():&lt;br /&gt;
    if g_debug: print &amp;quot;initializing squadless_kick script&amp;quot;&lt;br /&gt;
   &lt;br /&gt;
    host.registerHandler(&#039;PlayerSpawn&#039;, onPlayerSpawn)&lt;br /&gt;
    host.registerGameStatusHandler(onGameStatusChanged)&lt;br /&gt;
&lt;br /&gt;
# On spawn, checks if the player is in a squad or commanding.&lt;br /&gt;
# Player is added to kick list if not in a squad or not commanding.&lt;br /&gt;
def onPlayerSpawn(p, vehicle):&lt;br /&gt;
    global sks_debug&lt;br /&gt;
    global kickList, kickInterval&lt;br /&gt;
   &lt;br /&gt;
    if (p.getSquadId() == 0) and not p.isCommander():&lt;br /&gt;
        # Add the player if not in kick list&lt;br /&gt;
        if kickList.count(p.index) == 0:&lt;br /&gt;
            kickList.append(p.index)&lt;br /&gt;
&lt;br /&gt;
            # Set timer for kick&lt;br /&gt;
            bf2.Timer(onKickTimer, kickInterval, 1)&lt;br /&gt;
           &lt;br /&gt;
            if sks_debug: host.rcon_invoke(&amp;quot;echo \&amp;quot;&amp;quot; + p.getName() + &amp;quot; was added to the kick list.\&amp;quot;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        if sks_debug: host.rcon_invoke(&amp;quot;echo \&amp;quot;Kick warning issued.\&amp;quot;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        # Issue kick warning&lt;br /&gt;
        host.rcon_invoke(&amp;quot;game.sayAll \&amp;quot;ADMIN: |c1000&amp;quot; + p.getName() + &amp;quot; will be kicked for not being in a squad\&amp;quot;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
# Sends out warning messages&lt;br /&gt;
def onMsgTimer(data):&lt;br /&gt;
    global sks_debug&lt;br /&gt;
    global warningMsg&lt;br /&gt;
   &lt;br /&gt;
    host.rcon_invoke(&amp;quot;game.sayAll \&amp;quot;&amp;quot; + warningMsg + &amp;quot;\&amp;quot;&amp;quot;)&lt;br /&gt;
   &lt;br /&gt;
    if sks_debug: host.rcon_invoke(&amp;quot;echo \&amp;quot;Warning message issued.\&amp;quot;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
# Processes the kick list queue. The next player in queue&lt;br /&gt;
# is checked again and kicked if not in a squad or not commanding.&lt;br /&gt;
def onKickTimer(data):&lt;br /&gt;
    global sks_debug&lt;br /&gt;
    global kickList&lt;br /&gt;
&lt;br /&gt;
    if sks_debug: host.rcon_invoke(&amp;quot;echo \&amp;quot;Kick timer triggered.\&amp;quot;&amp;quot;)&lt;br /&gt;
   &lt;br /&gt;
    # Process the next player in queue.&lt;br /&gt;
    p = bf2.playerManager.getPlayerByIndex(kickList.pop(0))&lt;br /&gt;
   &lt;br /&gt;
    # Player is still squadless, kick him.&lt;br /&gt;
    if (p.getSquadId() == 0) and not p.isCommander():&lt;br /&gt;
        host.rcon_invoke(&amp;quot;echo \&amp;quot;&amp;quot; + p.getName() + &amp;quot; was kicked for not being in a squad\&amp;quot;&amp;quot;)&lt;br /&gt;
        host.rcon_invoke(&amp;quot;admin.kickPlayer &amp;quot; + str(p.index))&lt;br /&gt;
&lt;br /&gt;
# Handles clean up and initialization between rounds.&lt;br /&gt;
def onGameStatusChanged(status):&lt;br /&gt;
    global kickList&lt;br /&gt;
    global msgInterval, msgTimer&lt;br /&gt;
&lt;br /&gt;
    if status == bf2.GameStatus.Playing:&lt;br /&gt;
        host.rcon_invoke(&amp;quot;echo \&amp;quot;Game Status: Playing\&amp;quot;&amp;quot;)&lt;br /&gt;
       &lt;br /&gt;
        # Set the warning timer.&lt;br /&gt;
        msgTimer = bf2.Timer(onMsgTimer, msgInterval, 1)&lt;br /&gt;
        msgTimer.setRecurring(msgInterval)&lt;br /&gt;
&lt;br /&gt;
    elif status == bf2.GameStatus.PreGame:&lt;br /&gt;
        host.rcon_invoke(&amp;quot;echo \&amp;quot;Game Status: PreGame\&amp;quot;&amp;quot;)&lt;br /&gt;
       &lt;br /&gt;
        # Destroy any timers&lt;br /&gt;
        msgTimer.destroy()&lt;br /&gt;
        msgTimer = None&lt;br /&gt;
       &lt;br /&gt;
        # Blank the list.&lt;br /&gt;
        kickList = []&lt;br /&gt;
   &lt;br /&gt;
    elif status == bf2.GameStatus.EndGame:&lt;br /&gt;
        host.rcon_invoke(&amp;quot;echo \&amp;quot;Game Status: EndGame\&amp;quot;&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== History  ==&lt;br /&gt;
&lt;br /&gt;
0.1a&lt;br /&gt;
&lt;br /&gt;
- Basic squadless kick functionality at death&lt;br /&gt;
&lt;br /&gt;
- Warning message added&lt;br /&gt;
&lt;br /&gt;
0.2a&lt;br /&gt;
&lt;br /&gt;
- FIX: Players are not kicked when changing teams&lt;br /&gt;
&lt;br /&gt;
- Warning message can be set at a user specified interval&lt;br /&gt;
&lt;br /&gt;
- Kick list checks can be set at a user specified interval&lt;br /&gt;
&lt;br /&gt;
0.3a&lt;br /&gt;
&lt;br /&gt;
- FIX: Compatible with EA&#039;s autobalance script&lt;br /&gt;
&lt;br /&gt;
- Checks are now done when a player spawns&lt;br /&gt;
&lt;br /&gt;
- Message timer is destroyed when game ends and reinstantiated at game start&lt;br /&gt;
&lt;br /&gt;
- Improved kick delay; now works by a queue for consistent kick delays&lt;br /&gt;
&lt;br /&gt;
- Added debug flag for verbose server console messages&lt;/div&gt;</summary>
		<author><name>Pireax</name></author>
	</entry>
	<entry>
		<id>https://bf2tech.uturista.pt/index.php?title=Scripts:Autoteam_by_Tickets&amp;diff=114</id>
		<title>Scripts:Autoteam by Tickets</title>
		<link rel="alternate" type="text/html" href="https://bf2tech.uturista.pt/index.php?title=Scripts:Autoteam_by_Tickets&amp;diff=114"/>
		<updated>2018-06-22T15:31:28Z</updated>

		<summary type="html">&lt;p&gt;Pireax: Created page with &amp;quot;__TOC__ == Introduction  ==  I was toying with the idea of using the teamBalanceRatio server setting to alter the team balance based on team ticket counts. This script basical...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
== Introduction  ==&lt;br /&gt;
&lt;br /&gt;
I was toying with the idea of using the teamBalanceRatio server setting to alter the team balance based on team ticket counts. This script basically gives more people to the team with less tickets in inverse proportion to the ticket ratios. This little toy could be a real pain in the ass on servers where all users are eligible to be autoteamed, but some might find it useful anyway. We use it on our main server at [http://dontcamp.com/ Dontcamp.com] in conjuntion with a modified autoteam.py to basically put new players on the losing team. Should you want similar results, certain edits will have to be made to your autoteam.py. If you need more details, visit my website.&lt;br /&gt;
&lt;br /&gt;
== What It Does  ==&lt;br /&gt;
&lt;br /&gt;
If autoteam balance is on, the sever setting sv.teamRatioPercent is adjusted according to the current ticket ratio in favor of the team with less tickets on every [[Event_Reference#Player_Events|PlayerKilled]] event. Regardless of the sv.autoBalanceTeam value, sv.teamRatioPercent is saved on every &amp;lt;code&amp;gt;[[Object_Reference#bf2.GameStatus|GameStatus.PreGame]]&amp;lt;/code&amp;gt; Event, and restored on every &amp;lt;code&amp;gt;[[Object_Reference#bf2.GameStatus|GameStatus.EndGame]]&amp;lt;/code&amp;gt; Event. There are various reasons for this, and most come from my inability to see if sv.autoBalanceTeam has been toggled at any point. There are workaround to this that are more elegant, but none that I can see are as efficient as this one.&lt;br /&gt;
&lt;br /&gt;
== Comments  ==&lt;br /&gt;
&lt;br /&gt;
* I plan to add certain features to improve the user-friendliness of this script, such as stopping the automove when the team balance ratio gets to a certain degree, or if the game is coming to an end within &#039;x&#039; tickets or &#039;y&#039; seconds.&lt;br /&gt;
&lt;br /&gt;
* As with all scripts I write, my comments suck. I apologize --dst 22:36, 28 Jul 2005 (MDT) &lt;br /&gt;
&lt;br /&gt;
== dc_teamtickets.py  ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 #dontcamp.com Battlefield 2 auto team balance based on ticket ratio&lt;br /&gt;
 # v1.2&lt;br /&gt;
 #&lt;br /&gt;
 # Place in admin/standard_admin/&lt;br /&gt;
 # Add &amp;quot;import dc_teamtickets&amp;quot; and &amp;quot;dc_teamtickets.init()&amp;quot; to the __init__.py file in that directory.&lt;br /&gt;
 # Once this is imported, if auto team balance is on, the team balance ratio will be set inverse to the ticket ratio.&lt;br /&gt;
 #&lt;br /&gt;
 import host&lt;br /&gt;
 import bf2&lt;br /&gt;
 from bf2 import g_debug&lt;br /&gt;
 &lt;br /&gt;
 autobalance = 0&lt;br /&gt;
 originalratio = 0&lt;br /&gt;
 &lt;br /&gt;
 def init():&lt;br /&gt;
     if g_debug: print &#039;initializing Dontcamp.com Team/Ticket manager&#039;&lt;br /&gt;
     host.registerHandler(&#039;PlayerKilled&#039;, onPlayerKilled, 1)&lt;br /&gt;
     host.registerGameStatusHandler(onStatusChange)&lt;br /&gt;
 &lt;br /&gt;
 #Check ticket ratio every time someone get killed&lt;br /&gt;
 def onPlayerKilled(victimPlayerObject, attackerPlayerObject, weaponObject, assists, victimSoldierObject):&lt;br /&gt;
     global autobalance&lt;br /&gt;
     #if autobalance is off, don&#039;t change the ratio.&lt;br /&gt;
     autobalance = int(bf2.serverSettings.getAutoBalanceTeam())&lt;br /&gt;
     if autobalance:&lt;br /&gt;
         t1tickets = host.sgl_getParam(&#039;tickets&#039;, 1, 0)&lt;br /&gt;
         t2tickets = host.sgl_getParam(&#039;tickets&#039;, 2, 0)&lt;br /&gt;
        &lt;br /&gt;
         try:&lt;br /&gt;
             teamratio = int(float(t2tickets) / float(t1tickets) * 100)&lt;br /&gt;
             #hardcoded a cap of balance ratios to prevent ridiculous team stacking by autoteam&lt;br /&gt;
             #this is a 4/3 ratio&lt;br /&gt;
             if teamratio &amp;gt; 133: teamratio = 133&lt;br /&gt;
             if teamratio &amp;lt; 75: teamratio = 75&lt;br /&gt;
             host.rcon_invoke(&#039;sv.teamRatioPercent %d&#039; % teamratio)&lt;br /&gt;
         except ZeroDivisionError:&lt;br /&gt;
             pass&lt;br /&gt;
 &lt;br /&gt;
 #Grab the teamratiopercent on pregame, reset it on endgame.&lt;br /&gt;
 #Assuming that this is the only script messing with the ratio, all will be well.&lt;br /&gt;
 &lt;br /&gt;
 def onStatusChange(status):&lt;br /&gt;
     global originalratio&lt;br /&gt;
     if status == bf2.GameStatus.PreGame:&lt;br /&gt;
         originalratio = int(bf2.serverSettings.getTeamRatioPercent())&lt;br /&gt;
     if status == bf2.GameStatus.EndGame:&lt;br /&gt;
         host.rcon_invoke(&#039;sv.teamRatioPercent %d&#039; % originalratio)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
== __init__.py  ==&lt;br /&gt;
&lt;br /&gt;
Add these lines:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
import dc_teamtickets&lt;br /&gt;
dc_teamtickets.init()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Pireax</name></author>
	</entry>
	<entry>
		<id>https://bf2tech.uturista.pt/index.php?title=Scripts:AutoMap&amp;diff=113</id>
		<title>Scripts:AutoMap</title>
		<link rel="alternate" type="text/html" href="https://bf2tech.uturista.pt/index.php?title=Scripts:AutoMap&amp;diff=113"/>
		<updated>2018-06-22T15:31:12Z</updated>

		<summary type="html">&lt;p&gt;Pireax: Created page with &amp;quot;__TOC__ == Introduction  ==  With the 16/32/64 player map modes from BF2, I was upset to see that BF2 didn&amp;#039;t support dynamic scaling of the map size based on the number of pla...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
== Introduction  ==&lt;br /&gt;
&lt;br /&gt;
With the 16/32/64 player map modes from BF2, I was upset to see that BF2 didn&#039;t support dynamic scaling of the map size based on the number of players connected. I went ahead and threw something together to fix this issue. It also randomizes the map cycle. The randomization feature is currently hardcoded into the script.&lt;br /&gt;
&lt;br /&gt;
== What It Does  ==&lt;br /&gt;
&lt;br /&gt;
It gets its data from the server maplist file as defined in the server config file, defaulting to &amp;lt;code&amp;gt;mods/bf2/settings/maplist.con&amp;lt;/code&amp;gt;, on every &amp;lt;code&amp;gt;[[Object_Reference#bf2.GameStatus|GameStatus.Playing]]&amp;lt;/code&amp;gt; event thrown, so you can change it on the fly and invalid maps are still handled by the normal maplist parsing that hapens when bf2 loads up. It also sets the next map on this Event so that attempts to get the next map using &#039;admin.nextLevel&#039; will succeed. The size of the map, however, is decided on &amp;lt;code&amp;gt;[[Object_Reference#bf2.GameStatus|GameStatus.EndGame]]&amp;lt;/code&amp;gt; to ensure that the next map&#039;s size is set properly as close to the map change as possible.&lt;br /&gt;
&lt;br /&gt;
== Comments  ==&lt;br /&gt;
&lt;br /&gt;
* Currently, if there&#039;s only one map in the maplist, a loop will start and never, ever stop. If nobody beats me to it, I&#039;ll fix it soon. --Dst 14:04, 28 Jul 2005 (MDT)&lt;br /&gt;
&lt;br /&gt;
* If someone would be so kind as to make my commented instructions more user-friendly, I&#039;d be very grateful. --Dst 14:04, 28 Jul 2005 (MDT) &lt;br /&gt;
&lt;br /&gt;
== dc_automap.py  ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 #dontcamp.com Battlefield 2 automatic map changer/randomizer and maplist parser&lt;br /&gt;
 #&lt;br /&gt;
 # Place in admin/standard_admin/&lt;br /&gt;
 # Add &amp;quot;import dc_automap&amp;quot; and &amp;quot;dc_automap.init()&amp;quot; to the __init__.py file in that directory.&lt;br /&gt;
 # This works from the maps in your default maplist.con file. Please put more than one map in the file.&lt;br /&gt;
 #&lt;br /&gt;
 #&lt;br /&gt;
 # Set this to prevent maps being loaded if it played &amp;quot;n&amp;quot; number of maps ago, including the current map.&lt;br /&gt;
 maps_run_tracking = 3&lt;br /&gt;
 &lt;br /&gt;
 import host&lt;br /&gt;
 import bf2&lt;br /&gt;
 import random&lt;br /&gt;
 import re&lt;br /&gt;
 from bf2 import g_debug&lt;br /&gt;
 &lt;br /&gt;
 #init the maps_run list&lt;br /&gt;
 maps_run = []&lt;br /&gt;
 &lt;br /&gt;
 def init():&lt;br /&gt;
     if g_debug: print &#039;initializing DontCamp.com Automatic Map Changer, Randomizer and Parser&#039;&lt;br /&gt;
 &lt;br /&gt;
     host.registerGameStatusHandler(onGameStatusChanged)&lt;br /&gt;
 &lt;br /&gt;
 def onGameStatusChanged(status):&lt;br /&gt;
     global next_map&lt;br /&gt;
     global maps_run_tracking&lt;br /&gt;
 &lt;br /&gt;
       if status == bf2.GameStatus.Playing:&lt;br /&gt;
         current_map = bf2.gameLogic.getMapName()&lt;br /&gt;
        &lt;br /&gt;
         match_pattern = re.compile(r&#039;maplist.append &amp;quot;?(?P&amp;lt;map&amp;gt;.*?)&amp;quot;? &amp;quot;?gpm_[a-z]{2}&amp;quot;?( &amp;quot;?[0-9]{1,2}&amp;quot;?)?&#039;, re.I)&lt;br /&gt;
         map_list = []&lt;br /&gt;
         map_file = host.rcon_invoke(&#039;maplist.configFile&#039;)&lt;br /&gt;
 &lt;br /&gt;
         lines = 0&lt;br /&gt;
        &lt;br /&gt;
         for line in open(map_file.rstrip(&#039;\n&#039;)):&lt;br /&gt;
             match = match_pattern.match(line)&lt;br /&gt;
             map_list.append(match.group(&#039;map&#039;))&lt;br /&gt;
             lines += 1&lt;br /&gt;
 &lt;br /&gt;
         if lines &amp;lt; maps_run_tracking: maps_run_tracking = lines - 1&lt;br /&gt;
        &lt;br /&gt;
         maps_run.insert(0, current_map)&lt;br /&gt;
         if len(maps_run) &amp;gt; maps_run_tracking: maps_run.pop()&lt;br /&gt;
    &lt;br /&gt;
         next_map = current_map&lt;br /&gt;
 &lt;br /&gt;
         while next_map in maps_run:&lt;br /&gt;
             next_map = random.choice(map_list)&lt;br /&gt;
 &lt;br /&gt;
         host.rcon_invoke(&#039;maplist.clear&#039;)&lt;br /&gt;
         host.rcon_invoke(&#039;maplist.append %s gpm_cq&#039; % (next_map))&lt;br /&gt;
         host.rcon_invoke(&#039;admin.setnextlevel 0&#039;)&lt;br /&gt;
 &lt;br /&gt;
         if g_debug: print &#039;Next level set to %s, size will be determined on EndGame&#039; % (next_map)&lt;br /&gt;
    &lt;br /&gt;
     if status == bf2.GameStatus.EndGame:&lt;br /&gt;
         numplayers = 0&lt;br /&gt;
        &lt;br /&gt;
         for p in bf2.playerManager.getPlayers():&lt;br /&gt;
               numplayers += 1&lt;br /&gt;
 &lt;br /&gt;
         if numplayers &amp;gt;= 40:&lt;br /&gt;
             map_size = 64&lt;br /&gt;
         if numplayers &amp;lt; 40:&lt;br /&gt;
               map_size = 32&lt;br /&gt;
         if numplayers &amp;lt; 20:&lt;br /&gt;
             map_size = 16&lt;br /&gt;
    &lt;br /&gt;
         host.rcon_invoke(&#039;maplist.clear&#039;)&lt;br /&gt;
         host.rcon_invoke(&#039;maplist.append %s gpm_cq %d&#039; % (next_map, map_size))&lt;br /&gt;
           host.rcon_invoke(&#039;admin.setnextlevel 0&#039;)&lt;br /&gt;
        &lt;br /&gt;
         if g_debug: print &#039;Next level set to %s (%d)&#039; % (next_map, map_size)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
== __init__.py  ==&lt;br /&gt;
&lt;br /&gt;
Add these lines:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
import dc_automap&lt;br /&gt;
dc_automap.init()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Pireax</name></author>
	</entry>
	<entry>
		<id>https://bf2tech.uturista.pt/index.php?title=Scripts:AntiBaseRape&amp;diff=112</id>
		<title>Scripts:AntiBaseRape</title>
		<link rel="alternate" type="text/html" href="https://bf2tech.uturista.pt/index.php?title=Scripts:AntiBaseRape&amp;diff=112"/>
		<updated>2018-06-22T15:30:49Z</updated>

		<summary type="html">&lt;p&gt;Pireax: Created page with &amp;quot;__TOC__  == Description:  ==  ; Module : &amp;lt;code&amp;gt;AntiBaseRape.py&amp;lt;/code&amp;gt; ; Author : SHAnders ; Version : 1.11  Server side only admin script.  This script will punish players who...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== Description:  ==&lt;br /&gt;
&lt;br /&gt;
; Module&lt;br /&gt;
: &amp;lt;code&amp;gt;AntiBaseRape.py&amp;lt;/code&amp;gt;&lt;br /&gt;
; Author&lt;br /&gt;
: SHAnders&lt;br /&gt;
; Version&lt;br /&gt;
: 1.11&lt;br /&gt;
&lt;br /&gt;
Server side only admin script.&lt;br /&gt;
&lt;br /&gt;
This script will punish players who kill enemy within the area of a safe base. (Control point that can&#039;t be captured.)&lt;br /&gt;
&lt;br /&gt;
The punishment is the following:&lt;br /&gt;
&lt;br /&gt;
# The victims death score will be lowered by 1&lt;br /&gt;
# The attackers kill score will will be lowered by 1&lt;br /&gt;
# The attackers overall score will be lowered by 2 + number of warnings&lt;br /&gt;
# If warnings &amp;gt; 3 then...&lt;br /&gt;
&lt;br /&gt;
## The attackers TKs score will be increased by 1&lt;br /&gt;
## If attacker is on foot, he/she&#039;s health will be lowered to 0&lt;br /&gt;
## If attacker is in a vehicle, its health will be lowered to 1&lt;br /&gt;
&lt;br /&gt;
1 warning will be removed from players history every 2 minutes&lt;br /&gt;
&lt;br /&gt;
The radius for a safe base is set to 40. (Standard controlpoint capture area is 10.)&lt;br /&gt;
&lt;br /&gt;
== Installation as Admin script  ==&lt;br /&gt;
&lt;br /&gt;
# Save this script as &amp;lt;code&amp;gt;AntiBaseRape.py&amp;lt;/code&amp;gt; in your &amp;lt;code&amp;gt;admin/standard_admin&amp;lt;/code&amp;gt; directory.&lt;br /&gt;
# Add the lines &amp;lt;code&amp;gt;import AntiBaseRape&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;AntiBaseRape.init()&amp;lt;/code&amp;gt; to the file &amp;lt;code&amp;gt;admin/standard_admin/__init__.py&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== TODO:  ==&lt;br /&gt;
&lt;br /&gt;
Since not all maps are alike, the requirements for base rape protiction should be able to be altered individualy for each control point. &lt;br /&gt;
&lt;br /&gt;
== The Code  ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt; &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt; &amp;lt;/code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# Module: AntiBaseRape.py&lt;br /&gt;
# Author: SHAnders&lt;br /&gt;
#&lt;br /&gt;
# Version 1.11&lt;br /&gt;
#&lt;br /&gt;
# Changes:&lt;br /&gt;
#   v1.1 -&amp;gt; 1.11&lt;br /&gt;
#   Fixed the timer to only be started once&lt;br /&gt;
#   v1.0 -&amp;gt; 1.1&lt;br /&gt;
#   Implemted a baseRapeWarning attribute on players to count safe base kills&lt;br /&gt;
#   Implemted allowed amount of safe base kills (3)&lt;br /&gt;
#      up to this amount player only loses kill points + 1 score pr baseRapeWarning&lt;br /&gt;
#      over this amount player is allso killed&lt;br /&gt;
#   Implemtes a timer for removing 1 baseRapeWarning every 2 minutes&lt;br /&gt;
#&lt;br /&gt;
# Description:&lt;br /&gt;
#   Server side only admin script&lt;br /&gt;
#&lt;br /&gt;
#   This script will punish players who kill enemy within the area of a safe base&lt;br /&gt;
#  &lt;br /&gt;
# Requirements:&lt;br /&gt;
#   None.&lt;br /&gt;
#&lt;br /&gt;
# Installation as Admin script:&lt;br /&gt;
#   1: Save this script as &#039;AntiBaseRape.py&#039; in your &amp;lt;bf2&amp;gt;/admin/standard_admin directory.&lt;br /&gt;
#   2: Add the lines &#039;import AntiBaseRape&#039; and &#039;AntiBaseRape.init()&#039; to the file&lt;br /&gt;
#      &#039;&amp;lt;bf2&amp;gt;/admin/standard_admin/__init__.py&#039;.&lt;br /&gt;
#&lt;br /&gt;
# TODO:&lt;br /&gt;
#   Since not all maps are alike, the requirements for base rape protiction&lt;br /&gt;
#   should be able to be altered individualy for each control point.&lt;br /&gt;
#&lt;br /&gt;
# Thanks to:&lt;br /&gt;
#   Battlefield.no for inspiration from their pingkick.py script&lt;br /&gt;
#&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
import host&lt;br /&gt;
import bf2&lt;br /&gt;
import math&lt;br /&gt;
from bf2.stats.constants import *&lt;br /&gt;
from bf2 import g_debug&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# Constants&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
DEFAULT_SAFEBASE_RADIUS = 40 # Default safe area radius (normal commandpoint radius = 10)&lt;br /&gt;
ALLOWED_SAFEBASEKILLS = 3&lt;br /&gt;
SAFEBASEKILL_TIMER_INTERVAL = 120 # Intervals between removing a point from players.baseRapeWarning&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# Variables&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
 &lt;br /&gt;
WarnReduceTimer = None # Timer that reduces the warnings at intervals&lt;br /&gt;
 &lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# Init&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
 &lt;br /&gt;
def init():&lt;br /&gt;
   if g_debug: print &amp;quot;AntiBaseRape init&amp;quot;&lt;br /&gt;
   host.registerHandler(&#039;PlayerConnect&#039;, onPlayerConnect, 1)  &lt;br /&gt;
   host.registerHandler(&#039;PlayerKilled&#039;, onPlayerKilled)&lt;br /&gt;
 &lt;br /&gt;
   # Start the timer that reduces warnings on the SAFEBASEKILL_TIMER_INTERVAL&lt;br /&gt;
   WarnReduceTimer = bf2.Timer(onSafeBaseKillTimer, SAFEBASEKILL_TIMER_INTERVAL, 1)&lt;br /&gt;
   WarnReduceTimer.setRecurring(SAFEBASEKILL_TIMER_INTERVAL)&lt;br /&gt;
&lt;br /&gt;
   # Connect already connected players if reinitializing&lt;br /&gt;
   for p in bf2.playerManager.getPlayers():&lt;br /&gt;
      onPlayerConnect(p)&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
#  onPlayerConnect&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
def onPlayerConnect(player):&lt;br /&gt;
   resetPlayer(player)&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# onPlayerKilled&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
def onPlayerKilled(victim, attacker, weapon, assists, object):&lt;br /&gt;
   # killed by self&lt;br /&gt;
   if attacker == victim:&lt;br /&gt;
      pass&lt;br /&gt;
     &lt;br /&gt;
   # killed by enemy&lt;br /&gt;
   elif attacker != None and attacker.getTeam() != victim.getTeam():&lt;br /&gt;
      checkForSafeBase(attacker, victim)&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# Reset the bfno pingscript variables placed in the player object:&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
def resetPlayer(player):&lt;br /&gt;
   player.baseRapeWarning = 0&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# Check if victim was killed within safebase area&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
def checkForSafeBase(attacker, victim):&lt;br /&gt;
   victimVehicle = victim.getVehicle()&lt;br /&gt;
   controlPoints = bf2.objectManager.getObjectsOfType(&#039;dice.hfe.world.ObjectTemplate.ControlPoint&#039;)&lt;br /&gt;
   for cp in controlPoints:&lt;br /&gt;
      if cp.cp_getParam(&#039;unableToChangeTeam&#039;) != 0 and cp.cp_getParam(&#039;team&#039;) != attacker.getTeam():&lt;br /&gt;
         distanceTo = getVectorDistance(victimVehicle.getPosition(), cp.getPosition())&lt;br /&gt;
         if DEFAULT_SAFEBASE_RADIUS &amp;gt; float(distanceTo):&lt;br /&gt;
            justify(attacker, victim, cp, distanceTo)&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# Punish attacker, give victim life back and inform all&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
def justify(attacker, victim, controlPoint, distanceTo):&lt;br /&gt;
   victim.score.deaths += -1&lt;br /&gt;
   attacker.score.kills += -1&lt;br /&gt;
   attacker.score.score += -2 - attacker.baseRapeWarning&lt;br /&gt;
   attacker.baseRapeWarning += 1&lt;br /&gt;
   sendWarning(attacker, controlPoint, distanceTo)&lt;br /&gt;
   if attacker.baseRapeWarning &amp;gt; ALLOWED_SAFEBASEKILLS:&lt;br /&gt;
      attacker.score.TKs += 1&lt;br /&gt;
      if attacker.isAlive():&lt;br /&gt;
         vehicle = attacker.getVehicle()&lt;br /&gt;
         rootVehicle = getRootParent(vehicle)&lt;br /&gt;
         if getVehicleType(rootVehicle.templateName) == VEHICLE_TYPE_SOLDIER:&lt;br /&gt;
            rootVehicle.setDamage(0)&lt;br /&gt;
            # This should kill them !&lt;br /&gt;
         else:&lt;br /&gt;
            rootVehicle.setDamage(1)&lt;br /&gt;
            # a vehicle will likely explode within 1 sec killing entire crew,&lt;br /&gt;
            # not so sure about base defenses though&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# Send Warning&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
def sendWarning(player, controlPoint, distanceTo):&lt;br /&gt;
   mapName = bf2.gameLogic.getMapName()&lt;br /&gt;
   if player.baseRapeWarning &amp;gt; ALLOWED_SAFEBASEKILLS:&lt;br /&gt;
      sendMsgAll(player.getName() + &amp;quot; is punished for repeated violating of the no kill rules within safe base area&amp;quot;)&lt;br /&gt;
   else:&lt;br /&gt;
      sendMsgAll(player.getName() + &amp;quot; has violated of the no kill rules within safe base area &amp;quot; + str(player.baseRapeWarning) + &amp;quot; times now&amp;quot;)&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# remove baseRapeWarnings over time&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
def onSafeBaseKillTimer(data):&lt;br /&gt;
   for p in bf2.playerManager.getPlayers():&lt;br /&gt;
      if p.baseRapeWarning &amp;lt;= 0:&lt;br /&gt;
         p.baseRapeWarning = 0&lt;br /&gt;
      else:&lt;br /&gt;
         p.baseRapeWarning += -1&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# get distance between two positions&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
def getVectorDistance(pos1, pos2):&lt;br /&gt;
   diffVec = [0.0, 0.0, 0.0]&lt;br /&gt;
   diffVec[0] = math.fabs(pos1[0] - pos2[0])&lt;br /&gt;
   diffVec[1] = math.fabs(pos1[1] - pos2[1])&lt;br /&gt;
   diffVec[2] = math.fabs(pos1[2] - pos2[2])&lt;br /&gt;
  &lt;br /&gt;
   # Application of Pythagorean theorem to calculate total distance&lt;br /&gt;
   return math.sqrt(diffVec[0] * diffVec[0] + diffVec[1] * diffVec[1] + diffVec[2] * diffVec[2])&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# Send message to all on server&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
def sendMsgAll(msg):&lt;br /&gt;
   host.rcon_invoke(&amp;quot;game.sayAll \&amp;quot;&amp;quot; + str(msg) + &amp;quot;\&amp;quot;&amp;quot;)&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Pireax</name></author>
	</entry>
	<entry>
		<id>https://bf2tech.uturista.pt/index.php?title=Scripts:TXT_File_base_Automatic_Announcements&amp;diff=111</id>
		<title>Scripts:TXT File base Automatic Announcements</title>
		<link rel="alternate" type="text/html" href="https://bf2tech.uturista.pt/index.php?title=Scripts:TXT_File_base_Automatic_Announcements&amp;diff=111"/>
		<updated>2018-06-22T15:30:09Z</updated>

		<summary type="html">&lt;p&gt;Pireax: Created page with &amp;quot;I just finished this and it&amp;#039;s late, so I&amp;#039;m just going to throw it up and beef up the text later. It&amp;#039;s pretty well documented, so you shouldn&amp;#039;t have much trouble. Refer to Wood...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;I just finished this and it&#039;s late, so I&#039;m just going to throw it up and beef up the text later. It&#039;s pretty well documented, so you shouldn&#039;t have much trouble. Refer to Woody&#039;s [[Scripts:Automatic_Announcements|Automatic Announcements]] script for installation. The only change to that being that I had to install the script in the admin/default.py script. This could&#039;ve just been me, so keep in mind.&lt;br /&gt;
&lt;br /&gt;
NOTE: By default, logging is turned off since the files can get large, You should enable logging if you are having a problem and you need to debug it.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    advert.py - written by Dave Lawrence - thrash@fragnastika.com&lt;br /&gt;
   &lt;br /&gt;
    Based on Woody&#039;s &amp;quot;Automatic Announcements&amp;quot; script&lt;br /&gt;
    Loads messages from the text file &amp;quot;advert_msgs.txt&amp;quot;&lt;br /&gt;
        Use one line per message&lt;br /&gt;
    Log file can be used - advert_log.txt&lt;br /&gt;
        NOTE: Only use the log file for debug.  The output buffer is frequently&lt;br /&gt;
            flushed to ensure you see timely debug messages.  This *may* slow the&lt;br /&gt;
            game server down&lt;br /&gt;
    If you are having problems you can enable opt_SAdebug&lt;br /&gt;
        This will allow the script to run outside BF2&lt;br /&gt;
        There are no wrapers for the script, so the timer wont work, but you can&lt;br /&gt;
         debug probs with the message file&lt;br /&gt;
    NOTE: The advert_msgs.txt file is loaded into memory and I have no idea what&#039;ll&lt;br /&gt;
        happen if you try to use an enormous file.  Food for thought :)&lt;br /&gt;
&lt;br /&gt;
Release notes:&lt;br /&gt;
    advert.py v1.0&lt;br /&gt;
&lt;br /&gt;
ToDo:&lt;br /&gt;
    - Allow messages to be reloaded while the server is running (if that is even possible)&lt;br /&gt;
       Perhaps a command from the console&lt;br /&gt;
       Can anyone point me in the right direction on how to do this?&lt;br /&gt;
    - Put the dbgWriter class into it&#039;s own py so we can use it everywhere!&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
   Top-Level Imports&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
import sys&lt;br /&gt;
&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        OPTIONS&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
opt_Interval = 14   # Number of seconds between announcements&lt;br /&gt;
opt_SAdebug = 0     # For standalone debugging outside of bf2 enable this&lt;br /&gt;
# You can use this option to more easily figure out if your ads are loading&lt;br /&gt;
&lt;br /&gt;
# Enable logging to advert_log.txt&lt;br /&gt;
# Warning: only do this for debugging.  This log file could get huge!&lt;br /&gt;
opt_Debuglog = 0    # Logs to advert_log.txt&lt;br /&gt;
opt_Stdoutlog = 0   # Enable if you want ALL stdout msgs to be logged, you&#039;ll see the actual msh go out&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        GLOBALS&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
glob_dictMsgs = {}       # Where all the advert messages are stored&lt;br /&gt;
glob_hdlDbgout = {}&lt;br /&gt;
glob_IdxMsg = 0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    Functions and Classes&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
# This is where it happens :)&lt;br /&gt;
def tmrhdlAdvert(data):&lt;br /&gt;
    global glob_IdxMsg&lt;br /&gt;
    global glob_dictMsgs&lt;br /&gt;
    # Handle the index overflow&lt;br /&gt;
    if glob_IdxMsg &amp;gt;= len(glob_dictMsgs):&lt;br /&gt;
        glob_IdxMsg = 0&lt;br /&gt;
    host.rcon_invoke(&#039;game.sayall &amp;quot;%s&amp;quot;&#039; % glob_dictMsgs[glob_IdxMsg])&lt;br /&gt;
    dprint(&#039;game.sayall &amp;quot;%s&amp;quot;\n&#039; % glob_dictMsgs[glob_IdxMsg], 1)&lt;br /&gt;
    glob_IdxMsg += 1&lt;br /&gt;
&lt;br /&gt;
class dbgWriter:&lt;br /&gt;
    flog = {}&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        global glob_hdlDbgout&lt;br /&gt;
        glob_hdlDbgout = self&lt;br /&gt;
        if opt_Debuglog == 1 or opt_SAdebug == 0:&lt;br /&gt;
            self.flog = open(&#039;advert_log.txt&#039;, &#039;w&#039;)&lt;br /&gt;
            self.stream = self.flog&lt;br /&gt;
        else:&lt;br /&gt;
            self.stream = sys.stdout&lt;br /&gt;
&lt;br /&gt;
        # Do we modify STDOUT or leave it as the default cfg from somewhere else?&lt;br /&gt;
        if opt_Stdoutlog == 1:&lt;br /&gt;
            sys.stdout = self&lt;br /&gt;
&lt;br /&gt;
    def write(self, str):&lt;br /&gt;
        self.stream.write(str)&lt;br /&gt;
&lt;br /&gt;
    def prt(self, str):&lt;br /&gt;
        self.stream.write(str)&lt;br /&gt;
       &lt;br /&gt;
    def flush(self):&lt;br /&gt;
        self.stream.flush()&lt;br /&gt;
&lt;br /&gt;
def dprint(msg, flush=0):&lt;br /&gt;
    glob_hdlDbgout.prt(msg)&lt;br /&gt;
    if flush == 1:&lt;br /&gt;
        glob_hdlDbgout.flush()&lt;br /&gt;
       &lt;br /&gt;
&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
  Initialization and main code&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Init the debug writer&lt;br /&gt;
dbgWriter()&lt;br /&gt;
&lt;br /&gt;
dprint(&amp;quot;BF2 Advert Starting\n&amp;quot;, 1)&lt;br /&gt;
&lt;br /&gt;
# Check the interval and make sure it&#039;s not too short.  Let&#039;s clamp it at 15 secs&lt;br /&gt;
if opt_Interval &amp;lt; 15:&lt;br /&gt;
    dprint(&amp;quot;opt_Interval=%s which is too small, changing to 15 seconds\n&amp;quot; % opt_Interval)&lt;br /&gt;
    opt_Interval = 15&lt;br /&gt;
&lt;br /&gt;
# TODO: There should be some way to auto detect if we&#039;re running inside the BF2 engine, hmm :-\&lt;br /&gt;
# Allows BF2 modules to be disabled for local debugging&lt;br /&gt;
if(opt_SAdebug == 0):&lt;br /&gt;
    dprint(&amp;quot;Importing BF2 libs\n&amp;quot;, 1)&lt;br /&gt;
    import bf2&lt;br /&gt;
    import bf2.Timer&lt;br /&gt;
    import host&lt;br /&gt;
else:&lt;br /&gt;
    dprint(&amp;quot;Running in standalone mode\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
dprint(&amp;quot;Importing advertisment messages\n&amp;quot;, 1)&lt;br /&gt;
try:&lt;br /&gt;
    try:&lt;br /&gt;
        config = open(&#039;advert_msgs.cfg&#039;, &#039;rt&#039;)&lt;br /&gt;
    except:&lt;br /&gt;
        dprint(&amp;quot;Error opening advert_msgs.cfg- Is it missing?\n&amp;quot;)&lt;br /&gt;
    for line_ in config:&lt;br /&gt;
        line = line_.strip()&lt;br /&gt;
        if len(line) == 0 or line.startswith(&#039;#&#039;):  continue&lt;br /&gt;
        glob_dictMsgs[glob_IdxMsg] = line&lt;br /&gt;
        dprint(&amp;quot;%s\n&amp;quot; % glob_dictMsgs[glob_IdxMsg])&lt;br /&gt;
        glob_IdxMsg += 1&lt;br /&gt;
except IOError:&lt;br /&gt;
    dprint(&amp;quot;I/O Error on advert.cfg read - does it exist?\n&amp;quot;, 1)&lt;br /&gt;
    pass&lt;br /&gt;
&lt;br /&gt;
#Reset the glob_IdxMsg to point to the first message&lt;br /&gt;
glob_IdxMsg = 0&lt;br /&gt;
&lt;br /&gt;
# Let&#039;s make sure that the timer gets initialized correctly&lt;br /&gt;
# It works now, but EA could &amp;quot;F&amp;quot; us later :)&lt;br /&gt;
try:&lt;br /&gt;
    # We bypass this initialization if we&#039;re not running in BF2, this doesn;t *really* warrant a wrapper&lt;br /&gt;
    if opt_SAdebug == 0:&lt;br /&gt;
        timer = bf2.Timer(tmrhdlAdvert, opt_Interval, 1)&lt;br /&gt;
except:&lt;br /&gt;
    dprint(&amp;quot;&#039;timer = bf2.Timer(tmrhdlAdvert, 1)&#039; FAILED!!\n&amp;quot;, 1)&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    # We bypass this initialization if we&#039;re not running in BF2&lt;br /&gt;
    if opt_SAdebug == 0:&lt;br /&gt;
        timer.setRecurring(opt_Interval)&lt;br /&gt;
except:&lt;br /&gt;
    dprint(&amp;quot;&#039;timer.setRecurring(optInterval))&#039; FAILED!!\n&amp;quot;, 1)&lt;br /&gt;
&lt;br /&gt;
dprint(&amp;quot;tmrhadlAdvert istalled successfully\n&amp;quot;)&lt;br /&gt;
dprint(&amp;quot;BF2 Advert Started  %d messages\n&amp;quot; % len(glob_dictMsgs), 1)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Just call it advert.py, save it in admin/ and add the following to your admin/__init__.py or admin/default.py&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;import advert &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The advert_msgs.cfg file needs to be in the root BF2 directory. The log file, advert_log.txt will show up in the root BF2 folder as well.&lt;br /&gt;
&lt;br /&gt;
Have fun!&lt;/div&gt;</summary>
		<author><name>Pireax</name></author>
	</entry>
	<entry>
		<id>https://bf2tech.uturista.pt/index.php?title=Scripts:BF2Admin&amp;diff=110</id>
		<title>Scripts:BF2Admin</title>
		<link rel="alternate" type="text/html" href="https://bf2tech.uturista.pt/index.php?title=Scripts:BF2Admin&amp;diff=110"/>
		<updated>2018-06-22T15:27:51Z</updated>

		<summary type="html">&lt;p&gt;Pireax: Created page with &amp;quot;{{wip}}  This script so far, should read a file for a list of administrators listed by their profileID. This administrator can then use chat commands to kick and ban players....&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{wip}}&lt;br /&gt;
&lt;br /&gt;
This script so far, should read a file for a list of administrators listed by their profileID. This administrator can then use chat commands to kick and ban players.&lt;br /&gt;
&lt;br /&gt;
Last Update: 16:01, 10 Jul 2005 (CST)&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
== Documentation  ==&lt;br /&gt;
&lt;br /&gt;
Can be found in the [[Scripts:BF2Admin:Docs|BF2Admin Docs Page]]&lt;br /&gt;
&lt;br /&gt;
== Changes  ==&lt;br /&gt;
&lt;br /&gt;
* Added sa_add_admin &amp;lt;player&amp;gt; &amp;lt;permissions&amp;gt; which will write new admins to the users.cfg,&lt;br /&gt;
* Added pub_id &amp;lt;player&amp;gt; which print the profileID of a player to the requesters console,&lt;br /&gt;
* Corrected the playername matching function to ignore case, e.g. &amp;quot;sa_kick dan bad guy&amp;quot; will kick a player with the name like FSR|Danni&lt;br /&gt;
* Added sa_rcon &amp;lt;rconcmd&amp;gt; &amp;lt;args&amp;gt; to allow rcon commands to be executed, the results are not reported back.&lt;br /&gt;
* Made the permissions work&lt;br /&gt;
* Added configuration system&lt;br /&gt;
* Added squad/ping kicker&lt;br /&gt;
* Added immunity perm&lt;br /&gt;
&lt;br /&gt;
== To Do  ==&lt;br /&gt;
&lt;br /&gt;
* Reserved Slot for administrators,&lt;br /&gt;
* Rewrite the autobalancer to prioritze team switches,&lt;br /&gt;
* Administrator immunity from TKPunish&lt;br /&gt;
* Documentation (yeah right =P)&lt;br /&gt;
&lt;br /&gt;
== Requests?  ==&lt;br /&gt;
&lt;br /&gt;
* Using key hash instead of player name as auth method. --Wizzler 19:50, 7 Jul 2005 (MDT)&lt;br /&gt;
&#039;&#039;Actually, this method is nicer, as it ties the user back to their GameSpy ID and not to a certain install of BF2.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Bugs?  ==&lt;br /&gt;
&lt;br /&gt;
* ...&lt;br /&gt;
* ...&lt;br /&gt;
* ... &lt;br /&gt;
&lt;br /&gt;
== Files  ==&lt;br /&gt;
&lt;br /&gt;
File: bf2admin.py&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Ingame Administration System (BF2Admin)&lt;br /&gt;
#&lt;br /&gt;
# Author: Danni (webmaster@animelab.com)&lt;br /&gt;
# Clan: Fallen Soldiers Reborn&lt;br /&gt;
#&lt;br /&gt;
# http://www.fsrgaming.com&lt;br /&gt;
# http://www.animelab.com&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
# 100% Copyleft. Use at will but...&lt;br /&gt;
# If you reuse or modify this code you must credit me and&lt;br /&gt;
# the clan FSR. OR ELSE! &amp;gt;:D&lt;br /&gt;
#&lt;br /&gt;
# WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !!&lt;br /&gt;
#&lt;br /&gt;
# THIS MODULE IS NOT YET APPROVED FOR USE ON RANKED SERVERS!&lt;br /&gt;
# WE ARE NOT RESPONSIBLE FOR YOUR SERVER BEING DELISTED!&lt;br /&gt;
# PLEASE CHECK WITH EA FIRST BEFORE USING THIS MODULE ON A RANKED SERVER!&lt;br /&gt;
#&lt;br /&gt;
# WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !!&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
#       Special thanks        why?&lt;br /&gt;
#     _________________________________________________________________&lt;br /&gt;
#&lt;br /&gt;
#    Greeze            Inspiration from SayKick.py&lt;br /&gt;
#    DICE            tk_punish.py and other BF2 python sources&lt;br /&gt;
#    (unknown)        gui_log.pyw a VERY helpfull tool!&lt;br /&gt;
#    Everyone at BF2TIW    http://bf2.fun-o-matic.org/index.php/Main_Page&lt;br /&gt;
#&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
import string&lt;br /&gt;
import re&lt;br /&gt;
import bf2&lt;br /&gt;
import bf2.PlayerManager&lt;br /&gt;
import bf2.Timer&lt;br /&gt;
import host&lt;br /&gt;
from bf2 import g_debug&lt;br /&gt;
import bf2admincmd&lt;br /&gt;
import bf2adminkickers&lt;br /&gt;
&lt;br /&gt;
# Dictionaries. Duh!&lt;br /&gt;
pdict = { }&lt;br /&gt;
rcmd = { }&lt;br /&gt;
pcmd = { }&lt;br /&gt;
pinfo = { }&lt;br /&gt;
rinfo = { }&lt;br /&gt;
config = { }&lt;br /&gt;
log = None&lt;br /&gt;
&lt;br /&gt;
# Logging Levels&lt;br /&gt;
L_NONE         = 0&lt;br /&gt;
L_INFO         = 1&lt;br /&gt;
L_WARNING     = 2&lt;br /&gt;
L_ERROR     = 3&lt;br /&gt;
L_DEBUG        = 4&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class AdminData:&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        self.admin = 0&lt;br /&gt;
        self.perms = &amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class PlayerData:&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        self.lastupdate = 0&lt;br /&gt;
        self.lastupdate = 0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
### PlayerObject Extensions.&lt;br /&gt;
&lt;br /&gt;
def getPlayerPerms(self):&lt;br /&gt;
    return self.adminData.perms&lt;br /&gt;
&lt;br /&gt;
def isAdmin(self):&lt;br /&gt;
    return self.adminData.admin&lt;br /&gt;
&lt;br /&gt;
def sendMessage(self, message):&lt;br /&gt;
    host.sgl_sendTextMessage(self.index, 12, 1, message, 0)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
bf2.PlayerManager.Player.isAdmin = isAdmin&lt;br /&gt;
bf2.PlayerManager.Player.getPerms = getPlayerPerms&lt;br /&gt;
bf2.PlayerManager.Player.sendMessage = sendMessage&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def addChatCommand(command, function, perm, usage):&lt;br /&gt;
    rcmd[command] = function&lt;br /&gt;
    rinfo[command] = (perm, usage)&lt;br /&gt;
&lt;br /&gt;
def addPublicChatCommand(command, function, usage):&lt;br /&gt;
    pcmd[command] = function&lt;br /&gt;
    pinfo[command] = usage&lt;br /&gt;
&lt;br /&gt;
def setConfig(var, val):&lt;br /&gt;
    config[var] = val&lt;br /&gt;
&lt;br /&gt;
def getConfig(var):&lt;br /&gt;
    if config.has_key(var):&lt;br /&gt;
        return config[var]&lt;br /&gt;
    else:&lt;br /&gt;
        return False&lt;br /&gt;
&lt;br /&gt;
def out(level, string):&lt;br /&gt;
    global log&lt;br /&gt;
    LOGLEVEL = (&#039;[NONE]&#039;, &#039;[INFO]&#039;, &#039;[WARN]&#039;, &#039;[ERROR]&#039;, &#039;[DEBUG]&#039;)&lt;br /&gt;
    if not config.has_key(&#039;logging&#039;):&lt;br /&gt;
        config[&#039;logging&#039;] = 2&lt;br /&gt;
    if not config.has_key(&#039;loglevel&#039;):&lt;br /&gt;
        config[&#039;loglevel&#039;] = 3&lt;br /&gt;
&lt;br /&gt;
    string = LOGLEVEL[level] + &#039; &#039; + string&lt;br /&gt;
    if level &amp;lt;= config[&#039;loglevel&#039;]:&lt;br /&gt;
        if config[&#039;logging&#039;] &amp;gt;= 1:&lt;br /&gt;
            print string&lt;br /&gt;
        if config[&#039;logging&#039;] &amp;gt;= 2:&lt;br /&gt;
            sendAdminMessage(string)&lt;br /&gt;
        if config[&#039;logging&#039;] &amp;gt;= 3:&lt;br /&gt;
            log.write(string + &amp;quot;\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def loadConfig():&lt;br /&gt;
    fn = &#039;admin/bf2admin.cfg&#039;&lt;br /&gt;
&lt;br /&gt;
    try:&lt;br /&gt;
        cfg = open(fn, &#039;r&#039;)&lt;br /&gt;
        lineNo = 0&lt;br /&gt;
&lt;br /&gt;
        p = re.compile(&#039;(.*?):\s(.*?)&#039;, re.IGNORECASE)&lt;br /&gt;
&lt;br /&gt;
        for line in cfg:&lt;br /&gt;
            lineNo += 1&lt;br /&gt;
            if line.strip() != &#039;&#039; and line.strip() != &#039;\n&#039;:&lt;br /&gt;
                m = p.match(line)&lt;br /&gt;
                if m:&lt;br /&gt;
                    config[m.group(1)] = m.group(2)&lt;br /&gt;
&lt;br /&gt;
    except IOError, detail:&lt;br /&gt;
        out (L_WARNING, &#039;couldn\&#039;t read &amp;quot;%s&amp;quot;: %s&#039; % (fn, detail))&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
   &lt;br /&gt;
&lt;br /&gt;
def saveConfig():&lt;br /&gt;
    fn = &#039;admin/bf2admin.cfg&#039;&lt;br /&gt;
&lt;br /&gt;
    try:&lt;br /&gt;
        cfg = open(fn, &#039;w&#039;)&lt;br /&gt;
        lineNo = 0&lt;br /&gt;
&lt;br /&gt;
        keys = config.keys()&lt;br /&gt;
        keys.sort()&lt;br /&gt;
        for key in keys:&lt;br /&gt;
            cfg.write(str(key) + &#039;: &#039; + str(config[key]) + &#039;\n&#039;)&lt;br /&gt;
&lt;br /&gt;
    except IOError, detail:&lt;br /&gt;
        out(L_WARNING, &#039;couldn\&#039;t write &amp;quot;%s&amp;quot;: %s&#039; % (fn, detail))&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def sendAdminMessage(message):&lt;br /&gt;
    for tp in bf2.playerManager.getPlayers():&lt;br /&gt;
        if tp.adminData.admin:&lt;br /&gt;
            host.sgl_sendTextMessage(playerId, 12, 1, message, 0)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def findPlayerFromString(playpart):&lt;br /&gt;
    for tp in bf2.playerManager.getPlayers():&lt;br /&gt;
        name = tp.getName()&lt;br /&gt;
        playpart = playpart.lower()&lt;br /&gt;
        name = name.lower()&lt;br /&gt;
        if name.find(playpart) != -1:&lt;br /&gt;
            return tp&lt;br /&gt;
    return&lt;br /&gt;
&lt;br /&gt;
def findPlayerNameFromString(playpart):&lt;br /&gt;
    for tp in bf2.playerManager.getPlayers():&lt;br /&gt;
        name = tp.getName()&lt;br /&gt;
        playpart = playpart.lower()&lt;br /&gt;
        name = name.lower()&lt;br /&gt;
        if name.find(playpart) != -1:&lt;br /&gt;
            return tp.getName()&lt;br /&gt;
    return&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def init():&lt;br /&gt;
    global log&lt;br /&gt;
    out(L_INFO, &#039;initializing BF2Admin script&#039;)&lt;br /&gt;
    loadConfig()&lt;br /&gt;
    parseUsers()&lt;br /&gt;
    host.registerHandler(&#039;PlayerConnect&#039;, onPlayerConnect, 1)&lt;br /&gt;
    host.registerHandler(&#039;PlayerDisconnect&#039;, onPlayerDisconnect, 1)&lt;br /&gt;
    host.registerHandler(&#039;ChatMessage&#039;, onChatMessage, 1)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    fn = &#039;admin/logs/bf2admin.log&#039;&lt;br /&gt;
    try:&lt;br /&gt;
        log = open(fn, &#039;a&#039;)&lt;br /&gt;
   &lt;br /&gt;
    except IOError, detail:&lt;br /&gt;
        out(L_WARNING, &#039;couldn\&#039;t open &amp;quot;%s&amp;quot;: %s&#039; % (fn, detail))&lt;br /&gt;
&lt;br /&gt;
    bf2admincmd.init()&lt;br /&gt;
    bf2adminkickers.init()&lt;br /&gt;
&lt;br /&gt;
def stripmessage(text):&lt;br /&gt;
    text = text.replace(&amp;quot;HUD_TEXT_CHAT_TEAM&amp;quot;, &amp;quot;&amp;quot;)&lt;br /&gt;
    text = text.replace(&amp;quot;HUD_TEXT_CHAT_SQUAD&amp;quot;, &amp;quot;&amp;quot;)&lt;br /&gt;
    text = text.replace(&amp;quot;HUD_CHAT_DEADPREFIX&amp;quot;, &amp;quot;&amp;quot;)&lt;br /&gt;
    return text&lt;br /&gt;
&lt;br /&gt;
def onChatMessage(playerid, text, channel, flags):&lt;br /&gt;
    player = bf2.playerManager.getPlayerByIndex(playerid)&lt;br /&gt;
    text = stripmessage(text)&lt;br /&gt;
    cmdList = text.split(&#039; &#039;)&lt;br /&gt;
&lt;br /&gt;
    if len(cmdList) &amp;gt; 1 and playerid != -1:&lt;br /&gt;
        cmd = cmdList[0]&lt;br /&gt;
        cmdList[0:1] = []&lt;br /&gt;
        args = string.join(cmdList,&#039; &#039;)&lt;br /&gt;
        try:&lt;br /&gt;
            if player.adminData.admin and rinfo[cmd]:&lt;br /&gt;
                if player.adminData.perms.find(rinfo[cmd][0]) == -1:&lt;br /&gt;
                    player.sendMessage(player.index, &#039;BF2Admin:  You have no access to that command&#039;)&lt;br /&gt;
                else:&lt;br /&gt;
                    rcmd[cmd](player, args)&lt;br /&gt;
        except Exception, detail:&lt;br /&gt;
            out(L_DEBUG, &#039;Run-time error:&#039; + detail)&lt;br /&gt;
&lt;br /&gt;
        try:&lt;br /&gt;
            if pcmd[cmd] and pinfo[cmd]:&lt;br /&gt;
                pcmd[cmd](player, args)&lt;br /&gt;
        except Exception, detail:&lt;br /&gt;
            out(L_DEBUG, &#039;Run-time error:&#039; + detail)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def onPlayerConnect(player):&lt;br /&gt;
    player.adminData = AdminData()&lt;br /&gt;
    if pdict[str(player.getProfileId())]:&lt;br /&gt;
        player.adminData.admin = 1&lt;br /&gt;
        player.adminData.perms = str(pdict[str(player.getProfileId())])&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# This is just in case a playerslot is reused and not initalized correctly.&lt;br /&gt;
# and yes I have seen it happen in other games =P&lt;br /&gt;
&lt;br /&gt;
def onPlayerDisconnect(player):&lt;br /&gt;
    player.adminData = AdminData()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# Parses the config file, if it&#039;s there&lt;br /&gt;
def parseUsers():&lt;br /&gt;
    def boolFromString (str):&lt;br /&gt;
        if str in [&#039;True&#039;, &#039;true&#039;, &#039;1&#039;]:&lt;br /&gt;
            return True&lt;br /&gt;
        elif value in [&#039;False&#039;, &#039;false&#039;, &#039;0&#039;]:&lt;br /&gt;
            return False&lt;br /&gt;
        else:&lt;br /&gt;
            raise ValueError&lt;br /&gt;
&lt;br /&gt;
    fn = &#039;admin/users.cfg&#039;&lt;br /&gt;
    try:&lt;br /&gt;
&lt;br /&gt;
    # users.cfg format&lt;br /&gt;
    # Note: playername is purly so the maintainer can tell who a line is for&lt;br /&gt;
    #&lt;br /&gt;
    #&lt;br /&gt;
    # profileID    &amp;quot;playername&amp;quot;    &amp;quot;permissions&amp;quot;    &amp;quot;reserved&amp;quot;    &amp;quot;reserved&amp;quot; // Comment&lt;br /&gt;
    #&lt;br /&gt;
&lt;br /&gt;
        cfg = open(fn, &#039;r&#039;)&lt;br /&gt;
        lineNo = 0&lt;br /&gt;
&lt;br /&gt;
        # and now for some of that RegEx magic. ^_^&lt;br /&gt;
&lt;br /&gt;
        #            profileid    name     perms      resv     resv&lt;br /&gt;
        p = re.compile(&#039;\s*?([0-9]*?)\s\&amp;quot;(.*?)\&amp;quot;\s&amp;quot;(.*?)\&amp;quot;\s&amp;quot;(.*?)\&amp;quot;\s&amp;quot;(.*?)\&amp;quot;&#039;, re.IGNORECASE)&lt;br /&gt;
&lt;br /&gt;
        for line in cfg:&lt;br /&gt;
            lineNo += 1&lt;br /&gt;
            if line.strip() != &#039;&#039; and line.strip() != &#039;\n&#039;:&lt;br /&gt;
                m = p.match(line)&lt;br /&gt;
                if m:&lt;br /&gt;
                    pdict[m.group(1)] = m.group(3)&lt;br /&gt;
                   &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    except IOError, detail:&lt;br /&gt;
        out(L_WARNING, &#039;couldn\&#039;t read &amp;quot;%s&amp;quot;: %s&#039; % (fn, detail))&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
File: bf2admincmd.py&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Ingame Administration System (BF2Admin)&lt;br /&gt;
#&lt;br /&gt;
# Author: Danni (webmaster@animelab.com)&lt;br /&gt;
# Clan: Fallen Soldiers Reborn&lt;br /&gt;
#&lt;br /&gt;
# http://www.fsrgaming.com&lt;br /&gt;
# http://www.animelab.com&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
# 100% Copyleft. Use at will but...&lt;br /&gt;
# If you reuse or modify this code you must credit me and&lt;br /&gt;
# the clan FSR. OR ELSE! &amp;gt;:D&lt;br /&gt;
#&lt;br /&gt;
# WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !!&lt;br /&gt;
#&lt;br /&gt;
# THIS MODULE IS NOT YET APPROVED FOR USE ON RANKED SERVERS!&lt;br /&gt;
# WE ARE NOT RESPONSIBLE FOR YOUR SERVER BEING DELISTED!&lt;br /&gt;
# PLEASE CHECK WITH EA FIRST BEFORE USING THIS MODULE ON A RANKED SERVER!&lt;br /&gt;
#&lt;br /&gt;
# WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !!&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
#       Special thanks        why?&lt;br /&gt;
#     _________________________________________________________________&lt;br /&gt;
#&lt;br /&gt;
#    Greeze            Inspiration from SayKick.py&lt;br /&gt;
#    DICE            tk_punish.py and other BF2 python sources&lt;br /&gt;
#    (unknown)        gui_log.pyw a VERY helpfull tool!&lt;br /&gt;
#    Everyone at BF2TIW    http://bf2.fun-o-matic.org/index.php/Main_Page&lt;br /&gt;
#&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
import string&lt;br /&gt;
import re&lt;br /&gt;
import bf2&lt;br /&gt;
import host&lt;br /&gt;
import bf2.PlayerManager&lt;br /&gt;
import bf2admin&lt;br /&gt;
from bf2 import g_debug&lt;br /&gt;
# Logging Levels&lt;br /&gt;
L_NONE         = 0&lt;br /&gt;
L_INFO         = 1&lt;br /&gt;
L_WARNING     = 2&lt;br /&gt;
L_ERROR     = 3&lt;br /&gt;
L_DEBUG        = 4&lt;br /&gt;
&lt;br /&gt;
def init():&lt;br /&gt;
    bf2admin.out(L_INFO, &#039;initializing BF2AdminCmd script&#039;)&lt;br /&gt;
    bf2admin.addChatCommand(&#039;sa_kick&#039;,    sa_kick,    &#039;k&#039;,    &#039;sa_kick &amp;lt;player&amp;gt; &amp;lt;reason&amp;gt;   -   Kick a player&#039;)&lt;br /&gt;
    bf2admin.addChatCommand(&#039;sa_ban&#039;,    sa_ban,        &#039;b&#039;,    &#039;sa_ban &amp;lt;player&amp;gt; &amp;lt;length&amp;gt; &amp;lt;reason&amp;gt;   -   Ban a player&#039;)&lt;br /&gt;
    bf2admin.addChatCommand(&#039;sa_bankey&#039;,    sa_bankey,    &#039;b&#039;,    &#039;sa_bankey &amp;lt;player&amp;gt; &amp;lt;length&amp;gt; &amp;lt;reason&amp;gt;   -   Ban a player by CD-Key&#039;)&lt;br /&gt;
    bf2admin.addChatCommand(&#039;sa_rcon&#039;,    sa_rcon,    &#039;r&#039;,    &#039;sa_rcon &amp;lt;command&amp;gt; &amp;lt;args&amp;gt; ...   -   Send and rcon command&#039;)&lt;br /&gt;
    bf2admin.addChatCommand(&#039;sa_add_admin&#039;,    sa_add_admin,    &#039;f&#039;,    &#039;sa_add_admin &amp;lt;player&amp;gt; &amp;lt;permissions&amp;gt; ...   -   Add an administrator&#039;)&lt;br /&gt;
    bf2admin.addChatCommand(&#039;sa_save&#039;,    sa_save,    &#039;f&#039;,    &#039;sa_save &amp;lt;config&amp;gt;   -   Save the configuration&#039;)&lt;br /&gt;
    bf2admin.addChatCommand(&#039;sa_set&#039;,    sa_set,        &#039;f&#039;,    &#039;sa_set &amp;lt;key&amp;gt; &amp;lt;value&amp;gt;  -   Change a configuration option&#039;)&lt;br /&gt;
    bf2admin.addChatCommand(&#039;sa_get&#039;,    sa_get,        &#039;f&#039;,    &#039;sa_get &amp;lt;key&amp;gt;  -   Print a configuration option&#039;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    bf2admin.addPublicChatCommand(&#039;pub_id&#039;,     pub_id,     &#039;pub_id &amp;lt;player&amp;gt;   -   Retreave a players ProfileId&#039;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def sa_kick(issuer, args):&lt;br /&gt;
    argv = args.split(&#039; &#039;)&lt;br /&gt;
    playername = bf2admin.findPlayerNameFromString(argv[0])&lt;br /&gt;
    player = bf2admin.findPlayerFromString(argv[0])&lt;br /&gt;
    argv[0:1] = []&lt;br /&gt;
    reason = string.join(argv, &#039; &#039;)&lt;br /&gt;
    if playername:&lt;br /&gt;
        if player.getPerms().find(&#039;i&#039;) != -1:&lt;br /&gt;
            issuer.sendMessage(&#039;BF2Admin: &#039; + playername + &#039; is immune from that command&#039;)&lt;br /&gt;
        else:&lt;br /&gt;
            host.rcon_invoke(&#039;game.sayAll &amp;quot;BF2Admin: &#039; + playername + &#039; was kicked: &#039; + reason + &#039;&amp;quot;&#039;)&lt;br /&gt;
            host.rcon_invoke(&#039;admin.kickPlayer &amp;quot;&#039; + playername + &#039;&amp;quot;&#039;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def sa_ban(issuer, args):&lt;br /&gt;
    argv = args.split(&#039; &#039;)&lt;br /&gt;
    if not argv[2]:&lt;br /&gt;
        issuer.sendMessage(&amp;quot;usage: sa_ban &amp;lt;player&amp;gt; &amp;lt;length&amp;gt; &amp;lt;reason&amp;gt;&amp;quot;)&lt;br /&gt;
        return&lt;br /&gt;
    playername = bf2admin.findPlayerFromString(argv[0])&lt;br /&gt;
    player = bf2admin.findPlayerFromString(argv[0])&lt;br /&gt;
    length = int(argv[1])&lt;br /&gt;
    argv[0:2] = []&lt;br /&gt;
    reason = string.join(argv, &#039; &#039;)&lt;br /&gt;
    if playername:&lt;br /&gt;
        if player.getPerms().find(&#039;i&#039;) != -1:&lt;br /&gt;
            issuer.sendMessage(&#039;BF2Admin: &#039; + playername + &#039; is immune from that command&#039;)&lt;br /&gt;
        else:&lt;br /&gt;
            host.rcon_invoke(&#039;game.sayAll &amp;quot;BF2Admin: &#039; + playername + &#039; was banned: &#039; + reason + &#039;&amp;quot;&#039;)&lt;br /&gt;
            host.rcon_invoke(&#039;admin.banPlayer &#039; + player.index + &#039; &#039; + length)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def sa_bankey(issuer, args):&lt;br /&gt;
    argv = args.split(&#039; &#039;)&lt;br /&gt;
    if not argv[2]:&lt;br /&gt;
        issuer.sendMessage(&amp;quot;usage: sa_bankey &amp;lt;player&amp;gt; &amp;lt;length&amp;gt; &amp;lt;reason&amp;gt;&amp;quot;)&lt;br /&gt;
        return&lt;br /&gt;
    playername = bf2admin.findPlayerFromString(argv[0])&lt;br /&gt;
    player = bf2admin.findPlayerFromString(argv[0])&lt;br /&gt;
    length = int(argv[1])&lt;br /&gt;
    argv[0:2] = []&lt;br /&gt;
    reason = string.join(argv, &#039; &#039;)&lt;br /&gt;
    if playername:&lt;br /&gt;
        if player.getPerms().find(&#039;i&#039;) != -1:&lt;br /&gt;
            issuer.sendMessage(&#039;BF2Admin: &#039; + playername + &#039; is immune from that command&#039;)&lt;br /&gt;
        else:&lt;br /&gt;
            host.rcon_invoke(&#039;game.sayAll &amp;quot;BF2Admin: &#039; + playername + &#039;\&#039;s CD-KEY was banned: &#039; + reason + &#039;&amp;quot;&#039;)&lt;br /&gt;
            host.rcon_invoke(&#039;admin.banPlayerKey &#039; + player.index + &#039; &#039; + length)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def sa_save(issuer, args):&lt;br /&gt;
    bf2admin.saveConfig()&lt;br /&gt;
    issuer.sendMessage(&#039;BF2Admin: Configuration Saved&#039;)&lt;br /&gt;
&lt;br /&gt;
def sa_set(issuer, args):&lt;br /&gt;
    argv = args.split(&#039; &#039;)&lt;br /&gt;
    bf2admin.setConfig(argv[0], argv[1])&lt;br /&gt;
&lt;br /&gt;
def sa_get(issuer, args):&lt;br /&gt;
    issuer.sendMessage(&#039;BF2Admin: &#039; + str(args) + &#039;: &#039; + str(bf2admin.getConfig(args)))&lt;br /&gt;
   &lt;br /&gt;
&lt;br /&gt;
def sa_add_admin(issuer, args):&lt;br /&gt;
    # sa_add_admin playerName permissions&lt;br /&gt;
    argv = args.split(&#039; &#039;)&lt;br /&gt;
    playername = bf2admin.findPlayerNameFromString(argv[0])&lt;br /&gt;
    player = bf2admin.findPlayerFromString(argv[0])&lt;br /&gt;
    profileId = player.getProfileId()&lt;br /&gt;
    if player.getPerms():&lt;br /&gt;
        issuer.sendMessage(&#039;BF2Admin: &#039; + playername + &#039; is already an administrator. Please edit the users.cfg file manualy to change permissions&#039;)&lt;br /&gt;
    else:&lt;br /&gt;
        file = open(&#039;admin/users.cfg&#039;, &#039;a&#039;)&lt;br /&gt;
        file.write(&#039;    &#039; + str(profileId) + &#039;    &amp;quot;&#039; + playername + &#039;&amp;quot;    &amp;quot;&#039; + argv[1] +&#039;&amp;quot;    &amp;quot;&amp;quot;    &amp;quot;&amp;quot;\n&#039;)&lt;br /&gt;
        file.close()&lt;br /&gt;
        issuer.sendMessage(&#039;BF2Admin: &#039; + playername + &#039; added as an administrator.&#039;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def sa_rcon(issuer, args):&lt;br /&gt;
    argv = args.split(&#039; &#039;)&lt;br /&gt;
    argv[0:1] = []&lt;br /&gt;
    reason = string.join(argv, &#039; &#039;)&lt;br /&gt;
    res = host.rcon_invoke(args)&lt;br /&gt;
    issuer.sendMessage(&#039;BF2Admin: rcon command issued&#039;)   &lt;br /&gt;
    for line in res.split(&#039;\n&#039;):&lt;br /&gt;
        issuer.sendMessage(line)   &lt;br /&gt;
   &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def pub_id(issuer, args):&lt;br /&gt;
    argv = args.split(&#039; &#039;)&lt;br /&gt;
    tp = bf2admin.findPlayerFromString(argv[0])   &lt;br /&gt;
    if tp:&lt;br /&gt;
        issuer.sendMessage(&#039;BF2Admin: Name: &#039; + str(tp.getName()) + &#039;        ProfileId: &#039; + str(tp.getProfileId()))&lt;br /&gt;
    else:&lt;br /&gt;
        issuer.sendMessage(&#039;BF2Admin: Error: Could not find a player with that name&#039;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def pub_help(issuer, args):&lt;br /&gt;
    argv = args.split(&#039; &#039;)&lt;br /&gt;
    tp = bf2admin.findPlayerFromString(argv[0])   &lt;br /&gt;
    if tp:&lt;br /&gt;
        issuer.sendMessage(&#039;BF2Admin: Name: &#039; + str(tp.getName()) + &#039;        ProfileId: &#039; + str(tp.getProfileId()))&lt;br /&gt;
    else:&lt;br /&gt;
        issuer.sendMessage(&#039;BF2Admin: Error: Could not find a player with that name&#039;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
File: bf2adminkickers.py&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Ingame Administration System (BF2Admin)&lt;br /&gt;
#&lt;br /&gt;
# Author: Danni (webmaster@animelab.com)&lt;br /&gt;
# Clan: Fallen Soldiers Reborn&lt;br /&gt;
#&lt;br /&gt;
# http://www.fsrgaming.com&lt;br /&gt;
# http://www.animelab.com&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
# 100% Copyleft. Use at will but...&lt;br /&gt;
# If you reuse or modify this code you must credit me and&lt;br /&gt;
# the clan FSR. OR ELSE! &amp;gt;:D&lt;br /&gt;
#&lt;br /&gt;
# WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !!&lt;br /&gt;
#&lt;br /&gt;
# THIS MODULE IS NOT YET APPROVED FOR USE ON RANKED SERVERS!&lt;br /&gt;
# WE ARE NOT RESPONSIBLE FOR YOUR SERVER BEING DELISTED!&lt;br /&gt;
# PLEASE CHECK WITH EA FIRST BEFORE USING THIS MODULE ON A RANKED SERVER!&lt;br /&gt;
#&lt;br /&gt;
# WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !!&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
#       Special thanks        why?&lt;br /&gt;
#     _________________________________________________________________&lt;br /&gt;
#&lt;br /&gt;
#    Greeze            Inspiration from SayKick.py&lt;br /&gt;
#    DICE            tk_punish.py and other BF2 python sources&lt;br /&gt;
#    (unknown)        gui_log.pyw a VERY helpfull tool!&lt;br /&gt;
#    Everyone at BF2TIW    http://bf2.fun-o-matic.org/index.php/Main_Page&lt;br /&gt;
#&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
import string&lt;br /&gt;
import re&lt;br /&gt;
import bf2&lt;br /&gt;
import bf2.PlayerManager&lt;br /&gt;
import bf2.Timer&lt;br /&gt;
import host&lt;br /&gt;
from bf2 import g_debug&lt;br /&gt;
import bf2admin&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
gamestatus = None&lt;br /&gt;
ten_secs = None&lt;br /&gt;
sixty_secs = None&lt;br /&gt;
&lt;br /&gt;
bf2.PlayerManager.Player.pingWarnings = 0&lt;br /&gt;
bf2.PlayerManager.Player.squadWarnings = 0&lt;br /&gt;
bf2.PlayerManager.Player.detectedPing = []&lt;br /&gt;
bf2.PlayerManager.Player.pingSamples = 0&lt;br /&gt;
bf2.PlayerManager.Player.actuallyPlaying = False&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    def resetPlayer(p):&lt;br /&gt;
        p.pingWarnings = 0&lt;br /&gt;
        p.squadWarnings = 0&lt;br /&gt;
        p.detectedPing = []&lt;br /&gt;
        p.pingSamples = 0&lt;br /&gt;
        p.actuallyPlaying = False&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    def init():&lt;br /&gt;
        # defaults&lt;br /&gt;
        if not bf2admin.getConfig(&#039;pk_enabled&#039;):&lt;br /&gt;
            bf2admin.setConfig(&#039;pk_enabled&#039;, 1)&lt;br /&gt;
        if not bf2admin.getConfig(&#039;sk_enabled&#039;):&lt;br /&gt;
            bf2admin.setConfig(&#039;sk_enabled&#039;, 1)&lt;br /&gt;
   &lt;br /&gt;
        if not bf2admin.getConfig(&#039;pk_samples&#039;):&lt;br /&gt;
            bf2admin.setConfig(&#039;pk_samples&#039;, 12) # two minuites of samples&lt;br /&gt;
        if not bf2admin.getConfig(&#039;pk_warnings&#039;):&lt;br /&gt;
            bf2admin.setConfig(&#039;pk_warnings&#039;, 3)&lt;br /&gt;
        if not bf2admin.getConfig(&#039;pk_maxping&#039;):&lt;br /&gt;
            bf2admin.setConfig(&#039;pk_maxping&#039;, 1)&lt;br /&gt;
        if not bf2admin.getConfig(&#039;sk_warnings&#039;):&lt;br /&gt;
            bf2admin.setConfig(&#039;sk_warnings&#039;, 3)&lt;br /&gt;
   &lt;br /&gt;
   &lt;br /&gt;
        host.registerHandler(&#039;PlayerConnect&#039;, onPlayerConnect)&lt;br /&gt;
        host.registerHandler(&#039;PlayerDisconnect&#039;, onPlayerDisconnect)&lt;br /&gt;
        host.registerHandler(&#039;PlayerSpawn&#039;, onPlayerSpawn)&lt;br /&gt;
        host.registerHandler(&#039;PlayerDeath&#039;, onPlayerSpawn)&lt;br /&gt;
        host.registerGameStatusHandler(onGameStatusChanged)&lt;br /&gt;
        enableTimers()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    def enableTimers():&lt;br /&gt;
        global ten_secs&lt;br /&gt;
        global sixty_secs&lt;br /&gt;
&lt;br /&gt;
        if not ten_secs:&lt;br /&gt;
            ten_secs = bf2.Timer(ten_seconds, 10, 1)&lt;br /&gt;
        ten_secs.setRecurring(10)&lt;br /&gt;
        if not sixty_secs:&lt;br /&gt;
            sixty_secs = bf2.Timer(sixty_seconds, 60, 1)&lt;br /&gt;
        sixty_secs.setRecurring(60)&lt;br /&gt;
           &lt;br /&gt;
    def ten_seconds(data):&lt;br /&gt;
        # ping kick&lt;br /&gt;
        enableTimers()&lt;br /&gt;
   &lt;br /&gt;
           &lt;br /&gt;
           &lt;br /&gt;
   &lt;br /&gt;
    def sixty_seconds(data):&lt;br /&gt;
        enableTimers()&lt;br /&gt;
        for tp in bf2.playerManager.getPlayers():&lt;br /&gt;
            if bf2admin.getConfig(&#039;pk_enabled&#039;) and tp.actuallyPlaying:&lt;br /&gt;
                if tp.getPing() &amp;gt; bf2admin.getConfig(&#039;pk_maxping&#039;):&lt;br /&gt;
                    if tp.pingWarnings &amp;lt; bf2admin.getConfig(&#039;pk_warnings&#039;):&lt;br /&gt;
                        tp.pingWarnings += 1&lt;br /&gt;
                        tp.sendMessage(&#039;BF2Admin: WARNING &#039; + str(tp.pingWarnings) + &#039;/&#039; + str(bf2admin.getConfig(&#039;pk_warnings&#039;)) +&#039;! YOUR PING IS TOO HIGH! YOU WILL BE REMOVED IF IT DOES NOT FALL BELOW &#039; + str(bf2admin.getConfig(&#039;pk_maxping&#039;)) + &#039;!&#039;)&lt;br /&gt;
                    else:&lt;br /&gt;
                        host.rcon_invoke(&#039;game.sayAll &amp;quot;BF2Admin: &#039; + tp.getName() + &#039; was kicked due to high ping!&#039;)&lt;br /&gt;
                        host.rcon_invoke(&#039;admin.kickPlayer &amp;quot;&#039; + tp.getName() + &#039;&amp;quot;&#039;)&lt;br /&gt;
                else:&lt;br /&gt;
                    tp.pingWarnings = 0&lt;br /&gt;
   &lt;br /&gt;
            if bf2admin.getConfig(&#039;sk_enabled&#039;) and tp.actuallyPlaying:       &lt;br /&gt;
                if not tp.isCommander() and tp.getSquadId() == 0:&lt;br /&gt;
                    if tp.squadWarnings &amp;lt; bf2admin.getConfig(&#039;sk_warnings&#039;):&lt;br /&gt;
                        tp.squadWarnings += 1&lt;br /&gt;
                        tp.sendMessage(&#039;BF2Admin: WARNING &#039; + str(tp.squadWarnings) + &#039;/&#039; + str(bf2admin.getConfig(&#039;sk_warnings&#039;)) +&#039;! JOIN OR CREATE A SQUAD OR YOU WILL BE KICKED!&#039;)&lt;br /&gt;
                    else:&lt;br /&gt;
                        host.rcon_invoke(&#039;game.sayAll &amp;quot;BF2Admin: &#039; + tp.getName() + &#039; was kicked for not joining a squad!&#039;)&lt;br /&gt;
                        host.rcon_invoke(&#039;admin.kickPlayer &amp;quot;&#039; + tp.getName() + &#039;&amp;quot;&#039;)   &lt;br /&gt;
           &lt;br /&gt;
    def onPlayerSpawn(p, vehicle):&lt;br /&gt;
        enableTimers()&lt;br /&gt;
        p.actuallyPlaying = 1&lt;br /&gt;
   &lt;br /&gt;
    def onPlayerDeath(p, vehicle):&lt;br /&gt;
        p.actuallyPlaying = 1&lt;br /&gt;
           &lt;br /&gt;
    def onPlayerConnect(player):&lt;br /&gt;
        enableTimers()&lt;br /&gt;
        resetPlayer(player)&lt;br /&gt;
   &lt;br /&gt;
    def onPlayerDisconnect(player):&lt;br /&gt;
        enableTimers()&lt;br /&gt;
        resetPlayer(player)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    def onGameStatusChanged(status):&lt;br /&gt;
        gamestatus = status&lt;br /&gt;
       &lt;br /&gt;
        if gamestatus == bf2.GameStatus.EndGame:&lt;br /&gt;
            for tp in bf2.playerManager.getPlayers():&lt;br /&gt;
                tp.actuallyPlaying = 0&lt;br /&gt;
               &lt;br /&gt;
&lt;br /&gt;
except Exception, detail:&lt;br /&gt;
    print &#039;Error! &#039; + detail&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
File: users.cfg&lt;br /&gt;
&lt;br /&gt;
This file should be placed in the ./admin/ directory in the main BF2 directory.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# users.cfg # Administrator configuration file  # users.cfg format # Note: playername is purly so the maintainer can tell who a line is for # # profileID	&amp;quot;playername&amp;quot;	&amp;quot;permissions&amp;quot;	&amp;quot;reserved&amp;quot;	&amp;quot;reserved&amp;quot; // Comment   	44773626	&amp;quot;FSR|Danni&amp;quot;	&amp;quot;abcdefghijklmnopqrstuvwxyz1234567890&amp;quot; &amp;quot;&amp;quot; &amp;quot;&amp;quot; // Main Admin&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Pireax</name></author>
	</entry>
	<entry>
		<id>https://bf2tech.uturista.pt/index.php?title=Scripts:RconCfg&amp;diff=109</id>
		<title>Scripts:RconCfg</title>
		<link rel="alternate" type="text/html" href="https://bf2tech.uturista.pt/index.php?title=Scripts:RconCfg&amp;diff=109"/>
		<updated>2018-06-22T15:27:22Z</updated>

		<summary type="html">&lt;p&gt;Pireax: Created page with &amp;quot;__TOC__  == Introduction ==  Here&amp;#039;s a script that adds an rcon command called &amp;#039;cfg&amp;#039;. It is intended for server admins that want to execute several commands at once. For exampl...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
Here&#039;s a script that adds an rcon command called &#039;cfg&#039;. It is intended for server admins that want to execute several commands at once. For example to easily change server settings for switching between public/match-settings. The script supports unlimited number of config-files.&lt;br /&gt;
&lt;br /&gt;
== Installation ==&lt;br /&gt;
&lt;br /&gt;
# Place &amp;lt;code&amp;gt;cfg.py&amp;lt;/code&amp;gt; in the &amp;lt;code&amp;gt;BF2 Server Directory/admin/standard_admin/&amp;lt;/code&amp;gt; directory.&lt;br /&gt;
# Add a line in the &amp;lt;code&amp;gt;___init___.py&amp;lt;/code&amp;gt; file in the same directory that says &amp;lt;code&amp;gt;import cfg&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Make a directory called &amp;lt;code&amp;gt;cfg&amp;lt;/code&amp;gt; in the &amp;lt;code&amp;gt;BF2 Server Directory/admin/&amp;lt;/code&amp;gt; directory.&lt;br /&gt;
# Place your configs there, with the file-extension &amp;lt;code&amp;gt;.cfg&amp;lt;/code&amp;gt;, containing one command per line.&lt;br /&gt;
# Restart server, login through rcon and type &amp;lt;code&amp;gt;rcon cfg &amp;lt;config name without .cfg&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For example: &amp;lt;code&amp;gt;rcon cfg restart&amp;lt;/code&amp;gt; (to execute &amp;lt;code&amp;gt;BF2 Server Directory/admin/cfg/restart.cfg&amp;lt;/code&amp;gt;.)&lt;br /&gt;
&lt;br /&gt;
== The Code ==&lt;br /&gt;
&lt;br /&gt;
As you might see most of the script is copied from default.py&lt;br /&gt;
&lt;br /&gt;
&amp;lt;s&amp;gt;[http://truppo.mine.nu/truppo/cfg.py Download link for the script]&amp;lt;/s&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Updates ==&lt;br /&gt;
&lt;br /&gt;
2005-08-03: First version posted&lt;/div&gt;</summary>
		<author><name>Pireax</name></author>
	</entry>
	<entry>
		<id>https://bf2tech.uturista.pt/index.php?title=Scripts:RconMap&amp;diff=108</id>
		<title>Scripts:RconMap</title>
		<link rel="alternate" type="text/html" href="https://bf2tech.uturista.pt/index.php?title=Scripts:RconMap&amp;diff=108"/>
		<updated>2018-06-22T15:27:01Z</updated>

		<summary type="html">&lt;p&gt;Pireax: Created page with &amp;quot;__TOC__  == Introduction ==  Here&amp;#039;s a script that adds an rcon command called &amp;#039;map&amp;#039;. I&amp;#039;m not really a programmer so some of this can probably made in a better way but I&amp;#039;m just...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
Here&#039;s a script that adds an rcon command called &#039;map&#039;. I&#039;m not really a programmer so some of this can probably made in a better way but I&#039;m just glad I got it working. Wouldn&#039;t mind any tips on improvement though =).&lt;br /&gt;
&lt;br /&gt;
== Installation ==&lt;br /&gt;
&lt;br /&gt;
1. Place map.py in the &amp;lt;code&amp;gt;BF2 Server Directory/admin/standard_admin/&amp;lt;/code&amp;gt; directory&lt;br /&gt;
&lt;br /&gt;
2. Add a line in the &amp;lt;code&amp;gt;___init___.py&amp;lt;/code&amp;gt; file in the same directory that says &amp;lt;code&amp;gt;import map&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. Restart server, login through rcon and type &#039;rcon map&#039; for instructions&lt;br /&gt;
&lt;br /&gt;
== Update ==&lt;br /&gt;
&lt;br /&gt;
Version 0.2 doesn&#039;t clear the maplist any longer, it will instead search through your current maplist and append the map requested if it&#039;s not already in the rotation.  &lt;br /&gt;
&lt;br /&gt;
== The Code ==&lt;br /&gt;
&lt;br /&gt;
As you might see the script is easily customisable so you can add your own aliases if needed.&lt;br /&gt;
&lt;br /&gt;
[http://biomass.baconmen.net/map.py Download link for the script]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 # --------------------------------------&lt;br /&gt;
 # Battlefield 2 - rcon command &amp;quot;map&amp;quot; 0.2&lt;br /&gt;
 # --------------------------------------&lt;br /&gt;
 &lt;br /&gt;
 # Version history:&lt;br /&gt;
 #&lt;br /&gt;
 #    0.2    Made maplist check so that you won&#039;t loose your maplist when the map is changed&lt;br /&gt;
 #            through the command.&lt;br /&gt;
 #&lt;br /&gt;
 # Unnamed    First release. Basic map functionality.&lt;br /&gt;
 #&lt;br /&gt;
 &lt;br /&gt;
 # Written by biomass from Clan BaconMen (http://www.baconmen.net)&lt;br /&gt;
 # Thanks to Truppo for the inital inspiration =)&lt;br /&gt;
 # Lots of kudos to the people behind the BF2 Python Wiki.&lt;br /&gt;
 #&lt;br /&gt;
 # This scripts let you change maps through rcon without having to deal&lt;br /&gt;
 # with a maplist manually. It also allows you to use shorter names for&lt;br /&gt;
 # the different maps and currently if a map isn&#039;t in your maplist it&lt;br /&gt;
 # will be appended and added to that rotation..&lt;br /&gt;
 #&lt;br /&gt;
 # HOWTO Install:&lt;br /&gt;
 #&lt;br /&gt;
 # 1. Place map.py in the &amp;lt;BF2 Server Directory/admin/standard_admin/&amp;gt; directory&lt;br /&gt;
 # 2. Add a line in the ___init___.py file in the same directory that says&lt;br /&gt;
 #    import map&lt;br /&gt;
 # 3. Restart server, login through rcon and type &#039;rcon map&#039; for instructions&lt;br /&gt;
 #&lt;br /&gt;
 # That&#039;s it =)&lt;br /&gt;
 &lt;br /&gt;
 import default&lt;br /&gt;
 import new&lt;br /&gt;
 import string&lt;br /&gt;
 import host&lt;br /&gt;
 import re&lt;br /&gt;
 &lt;br /&gt;
 def rcmd_map(self, ctx, cmd):&lt;br /&gt;
     shortmaps = {&lt;br /&gt;
     &#039;dalian&#039;: &#039;dalian_plant&#039;,&lt;br /&gt;
     &#039;plant&#039;: &#039;dalian_plant&#039;,&lt;br /&gt;
     &#039;dalian_plant&#039;: &#039;dalian_plant&#039;,&lt;br /&gt;
     &#039;daqing&#039;: &#039;daqing_oilfields&#039;,&lt;br /&gt;
     &#039;oilfields&#039;: &#039;daqing_oilfields&#039;,&lt;br /&gt;
     &#039;daqing_oilfields&#039;: &#039;daqing_oilfields&#039;,&lt;br /&gt;
     &#039;dragon&#039;: &#039;dragon_valley&#039;,&lt;br /&gt;
     &#039;valley&#039;: &#039;dragon_valley&#039;,&lt;br /&gt;
     &#039;dragon_valley&#039;: &#039;dragon_valley&#039;,&lt;br /&gt;
     &#039;fushe&#039;: &#039;fushe_pass&#039;,&lt;br /&gt;
     &#039;pass&#039;: &#039;fushe_pass&#039;,&lt;br /&gt;
     &#039;fushe_pass&#039;: &#039;fushe_pass&#039;,&lt;br /&gt;
     &#039;gulf&#039;: &#039;gulf_of_oman&#039;,&lt;br /&gt;
     &#039;oman&#039;: &#039;gulf_of_oman&#039;,&lt;br /&gt;
     &#039;gulf_of_oman&#039;: &#039;gulf_of_oman&#039;,&lt;br /&gt;
     &#039;kubra&#039;: &#039;kubra_dam&#039;,&lt;br /&gt;
     &#039;dam&#039;: &#039;kubra_dam&#039;,&lt;br /&gt;
     &#039;kubra_dam&#039;: &#039;kubra_dam&#039;,&lt;br /&gt;
     &#039;mashtuur&#039;: &#039;mashtuur_city&#039;,&lt;br /&gt;
     &#039;city&#039;: &#039;mashtuur_city&#039;,&lt;br /&gt;
     &#039;mashtuur_city&#039;: &#039;mashtuur_city&#039;,&lt;br /&gt;
     &#039;clean&#039;: &#039;operation_clean_sweep&#039;,&lt;br /&gt;
     &#039;sweep&#039;: &#039;operation_clean_sweep&#039;,&lt;br /&gt;
     &#039;operation&#039;: &#039;operation_clean_sweep&#039;,&lt;br /&gt;
     &#039;operation_clean_sweep&#039;: &#039;operation_clean_sweep&#039;,&lt;br /&gt;
     &#039;sharqi&#039;: &#039;sharqi_peninsula&#039;,&lt;br /&gt;
     &#039;peninsula&#039;: &#039;sharqi_peninsula&#039;,&lt;br /&gt;
     &#039;sharqi_peninsula&#039;: &#039;sharqi_peninsula&#039;,&lt;br /&gt;
     &#039;strike&#039;: &#039;strike_at_karkand&#039;,&lt;br /&gt;
     &#039;karkand&#039;: &#039;strike_at_karkand&#039;,&lt;br /&gt;
     &#039;strike_at_karkand&#039;: &#039;strike_at_karkand&#039;,&lt;br /&gt;
     &#039;songhua&#039;: &#039;songhua_stalemate&#039;,&lt;br /&gt;
     &#039;stalemate&#039;: &#039;songhua_stalemate&#039;,&lt;br /&gt;
     &#039;songhua_stalemate&#039;: &#039;songhua_stalemate&#039;,&lt;br /&gt;
     &#039;zatar&#039;: &#039;zatar_wetlands&#039;,&lt;br /&gt;
     &#039;wetlands&#039;: &#039;zatar_wetlands&#039;,&lt;br /&gt;
     &#039;zatar_wetlands&#039;: &#039;zatar_wetlands&#039;&lt;br /&gt;
     }&lt;br /&gt;
     maperror = 0&lt;br /&gt;
     mapinmaplist = 0&lt;br /&gt;
     if cmd != &amp;quot;&amp;quot;:&lt;br /&gt;
         mapvars = cmd.split()&lt;br /&gt;
         if len(mapvars) == 1:&lt;br /&gt;
             if mapvars[0] == &#039;list&#039;:&lt;br /&gt;
                 maperror = 2&lt;br /&gt;
                 for m in shortmaps:&lt;br /&gt;
                     ctx.write(m + &#039;, &#039;)&lt;br /&gt;
             elif shortmaps.has_key(mapvars[0]):&lt;br /&gt;
                 ctx.write(&#039;Please specify playersize...\n&#039;)&lt;br /&gt;
                 maperror = 1&lt;br /&gt;
             else:&lt;br /&gt;
                 ctx.write(&#039;Unknown map...\n&#039;)&lt;br /&gt;
                 maperror = 1&lt;br /&gt;
         if len(mapvars) &amp;gt;= 2:&lt;br /&gt;
             if not shortmaps.has_key(mapvars[0]):&lt;br /&gt;
                 maperror = 1&lt;br /&gt;
                 ctx.write(&#039;Unknown map...\n&#039;)&lt;br /&gt;
             try:&lt;br /&gt;
                 if int(mapvars[1]) not in [16,32,64]:&lt;br /&gt;
                     maperror = 1&lt;br /&gt;
                     ctx.write(&#039;Unknown playersize...\n&#039;)&lt;br /&gt;
             except ValueError:&lt;br /&gt;
                 ctx.write(&#039;Unknown playersize...\n&#039;)&lt;br /&gt;
                 maperror = 1&lt;br /&gt;
     else:&lt;br /&gt;
         maperror = 1&lt;br /&gt;
     if int(maperror) == 1:&lt;br /&gt;
         ctx.write(&#039;\n&#039;)&lt;br /&gt;
         ctx.write(&#039;map: USAGE: rcon map (partial mapword or complete mapname) (playersize 16/32/64)\n&#039;)&lt;br /&gt;
         ctx.write(&#039;map: USAGE: rcon map list  - prints a list of valid aliases/names\n&#039;)&lt;br /&gt;
     elif int(maperror) == 2:&lt;br /&gt;
         ctx.write(&#039;end of maplist\n&#039;)&lt;br /&gt;
     else:&lt;br /&gt;
         maplist = serverConfig(&amp;quot;maplist.list&amp;quot;)&lt;br /&gt;
         pattern = re.compile(&#039;^\d+:\s\&amp;quot;(.*?)\&amp;quot;\sgpm_cq\s(\d{2})$&#039;, re.MULTILINE)&lt;br /&gt;
         result = []&lt;br /&gt;
         for maplist in pattern.findall(maplist):&lt;br /&gt;
             result.append((maplist[0].lower(),maplist[1]))&lt;br /&gt;
         for mapavailable in result:&lt;br /&gt;
             if str(mapavailable[0]) == shortmaps[mapvars[0]]:&lt;br /&gt;
                 if int(mapavailable[1]) == int(mapvars[1]):&lt;br /&gt;
                     mapinmaplist = 1&lt;br /&gt;
         if mapinmaplist != 0:&lt;br /&gt;
             host.rcon_invoke(&amp;quot;admin.nextLevel &amp;quot; + str(result.index((shortmaps[mapvars[0]],mapvars[1]))))&lt;br /&gt;
             host.rcon_invoke(&amp;quot;admin.runNextLevel&amp;quot;)&lt;br /&gt;
             ctx.write(&#039;Map in maplist - Changing map to &#039; + shortmaps[mapvars[0]] + &#039; - &#039; + mapvars[1] + &#039; players\n&#039;)&lt;br /&gt;
         else:&lt;br /&gt;
             ctx.write(&#039;Changing map to &#039; + shortmaps[mapvars[0]] + &#039; - &#039; + mapvars[1] + &#039; players\n&#039;)&lt;br /&gt;
             host.rcon_invoke(&#039;mapList.append &#039; + shortmaps[mapvars[0]] + &#039; gpm_cq &#039; + mapvars[1])&lt;br /&gt;
             host.rcon_invoke(&amp;quot;game.sayAll \&amp;quot;Changing map to &amp;quot; + shortmaps[mapvars[0]] + &amp;quot; - &amp;quot; + mapvars[1] + &amp;quot; players\&amp;quot;&amp;quot;)&lt;br /&gt;
             host.rcon_invoke(&amp;quot;admin.nextLevel &amp;quot; + str(len(result)))&lt;br /&gt;
             host.rcon_invoke(&amp;quot;admin.runNextLevel&amp;quot;)&lt;br /&gt;
 &lt;br /&gt;
 newMethod = new.instancemethod(rcmd_map, default.server, default.AdminServer)&lt;br /&gt;
 &lt;br /&gt;
 default.AdminServer.rcmd_map = newMethod&lt;br /&gt;
 &lt;br /&gt;
 default.server.rcon_cmds[&#039;map&#039;] = default.AdminServer.rcmd_map&lt;br /&gt;
 &lt;br /&gt;
 def serverConfig(variableName):&lt;br /&gt;
     return host.rcon_invoke(variableName).strip()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Updates =&lt;br /&gt;
&lt;br /&gt;
2005-Jul-30: Version 0.2 posted&lt;br /&gt;
&lt;br /&gt;
earlier date: First version posted&lt;/div&gt;</summary>
		<author><name>Pireax</name></author>
	</entry>
	<entry>
		<id>https://bf2tech.uturista.pt/index.php?title=Scripts:BadWords&amp;diff=107</id>
		<title>Scripts:BadWords</title>
		<link rel="alternate" type="text/html" href="https://bf2tech.uturista.pt/index.php?title=Scripts:BadWords&amp;diff=107"/>
		<updated>2018-06-22T15:26:45Z</updated>

		<summary type="html">&lt;p&gt;Pireax: Created page with &amp;quot;==  Introduction  ==  I own a cybercafe / game center where the most popular game is BF2. Most of our customers are teenagers, but we get quite a few younger and older gamers,...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==  Introduction  ==&lt;br /&gt;
&lt;br /&gt;
I own a cybercafe / game center where the most popular game is BF2. Most of our customers are teenagers, but we get quite a few younger and older gamers, too. The parents of the younger ones are naturally concerned about some of the language used in chat messages in online games; even quite a few older gamers find some of racist and related language used by some online gamers to be offensive. To help keep our servers feeling friendly to everyone, I wrote this script.&lt;br /&gt;
&lt;br /&gt;
The basic idea is that when the server starts, the script reads a configuration file that contains words you want to prohibit players from using in their names and chat messages; the format of the file is just a list of &amp;quot;bad&amp;quot; words, one per line. Every time a player connects, the script scans the players name for the presence of any of bad words; every time a player sends a chat message, the chat message is similarly scanned. If the script finds any of the bad words in a name or chat message, the player is immediately kicked using the PunkBuster kick facility (so that they can be given a meaningful reason why they were kicked), other players are notified about what happened to them, and a log message is printed.&lt;br /&gt;
&lt;br /&gt;
The name of the file containing the list of bad words, and the length of time they will be kicked for, are set in variables at the beginning of the script. NOTE: be careful with your choices of words for the bad words file--the script is written to catch these words occuring in any kind of substring in chat messages and names, so if you&#039;re not careful you can find your server is kicking people who are using perfectly innocent names.&lt;br /&gt;
&lt;br /&gt;
It&#039;s probably also a good idea to warn people if you&#039;re using software like this on your server: use a script like [[Scripts:Automatic_Announcements|this]] or [[Scripts:TXT_File_base_Automatic_Announcements|this]], for example, to tell people they will be automatically kicked if they use inappropriate language.&lt;br /&gt;
&lt;br /&gt;
To install the script, just &amp;lt;code&amp;gt;import&amp;lt;/code&amp;gt; it from one of the main BF2 scripts, such as &amp;lt;code&amp;gt;Battlefield 2 Server/admin/default.py&amp;lt;/code&amp;gt; &lt;br /&gt;
&lt;br /&gt;
== Code  ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 &#039;&#039;&#039;badWords: Module to kick players for using &amp;quot;bad&amp;quot; words.&lt;br /&gt;
   &lt;br /&gt;
    Version 0.01, 2005 August 3, Forrest Thiessen&#039;&#039;&#039;&lt;br /&gt;
 &lt;br /&gt;
 #Copyright (c) 2005 Cyberscape Enterprises, Inc., www.cyberscapearena.com&lt;br /&gt;
 #&lt;br /&gt;
 #Permission is hereby granted, free of charge, to any person obtaining a&lt;br /&gt;
 #copy of this software and associated documentation files (the &amp;quot;Software&amp;quot;),&lt;br /&gt;
 #to deal in the Software without restriction, including without limitation&lt;br /&gt;
 #the rights to use, copy, modify, merge, publish, distribute, sublicense,&lt;br /&gt;
 #and/or sell copies of the Software, and to permit persons to whom the&lt;br /&gt;
 #Software is furnished to do so, subject to the following conditions:&lt;br /&gt;
 #&lt;br /&gt;
 #The above copyright notice and this permission notice shall be included&lt;br /&gt;
 #in all copies or substantial portions of the Software.&lt;br /&gt;
 #&lt;br /&gt;
 #THE SOFTWARE IS PROVIDED &amp;quot;AS IS&amp;quot;, WITHOUT WARRANTY OF ANY KIND, EXPRESS&lt;br /&gt;
 #OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,&lt;br /&gt;
 #FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE&lt;br /&gt;
 #AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER&lt;br /&gt;
 #LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING&lt;br /&gt;
 #FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER&lt;br /&gt;
 #DEALINGS IN THE SOFTWARE.&lt;br /&gt;
 #&lt;br /&gt;
 #Battlefield 2 is a trademark of Digital Illusions CE AB. Electronic Arts,&lt;br /&gt;
 #EA, EA GAMES and the EA GAMES logo are trademarks or registered trademarks&lt;br /&gt;
 #of Electronic Arts Inc. in the U.S. and/or other countries. EA GAMES(tm) is&lt;br /&gt;
 #an Electronic Arts(tm) brand.&lt;br /&gt;
 &lt;br /&gt;
 import host&lt;br /&gt;
 import bf2&lt;br /&gt;
 import time&lt;br /&gt;
 &lt;br /&gt;
 badWordsFileName = &amp;quot;admin/BadWords.con&amp;quot;  # File containing list of bad words, one per line&lt;br /&gt;
 kickTime = 10   # Default kick time in seconds&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 badWords = []&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 # Open the file, read the bad word list, and register handlers&lt;br /&gt;
 try:&lt;br /&gt;
     badWordsFile = open(badWordsFileName, &#039;r&#039;)&lt;br /&gt;
     # Read the file into a list, each element being one bad word&lt;br /&gt;
     badWords = [word.strip() for word in badWordsFile.readlines()]&lt;br /&gt;
    &lt;br /&gt;
     # Register handlers to receive chat messages and player connections&lt;br /&gt;
     host.registerHandler(&#039;ChatMessage&#039;, onChatMessage, 1)&lt;br /&gt;
     host.registerHandler(&#039;PlayerConnect&#039;, onPlayerConnect, 1)&lt;br /&gt;
    &lt;br /&gt;
     print &#039;BadWords: BadWords module initialized with&#039;, len(badWords), &#039;words.&#039;&lt;br /&gt;
 &lt;br /&gt;
 except IOError:&lt;br /&gt;
     print &amp;quot;BadWords: Couldn&#039;t open bad words file&amp;quot;, fileName&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 # As players connect to the server, check if their names contain any of&lt;br /&gt;
 # the bad words, and kick them if they do.&lt;br /&gt;
 def onPlayerConnect(playerObject):&lt;br /&gt;
     global badWords, kickTime&lt;br /&gt;
    &lt;br /&gt;
     name = playerObject.getName()&lt;br /&gt;
    &lt;br /&gt;
     for word in badWords:&lt;br /&gt;
         if name.find(word) == -1: continue&lt;br /&gt;
        &lt;br /&gt;
         host.rcon_invoke(&#039;game.sayall &amp;quot;Player %s kicked for having an inappropriate name&amp;quot;&#039;&lt;br /&gt;
                          % playerName)&lt;br /&gt;
         host.rcon_invoke(&#039;pb_sv_kick &amp;quot;%s&amp;quot; %i &amp;quot;Inappropriate name&amp;quot;&#039;&lt;br /&gt;
                          % (playerName, kickTime))&lt;br /&gt;
         print ( &#039;BadWords: Player %s kicked for having inappropriate name at %s&#039;&lt;br /&gt;
                 % (playerName, time.strftime(&amp;quot;%a %d-%b-%Y %H:%M&amp;quot;)) )&lt;br /&gt;
        &lt;br /&gt;
         break&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 # Whenever a chat message is sent on any channel, check it for bad words; if&lt;br /&gt;
 # there are any, kick the player who sent the message.&lt;br /&gt;
 def onChatMessage(playerID, msgText, channel, flags):&lt;br /&gt;
     global badWords, kickTime&lt;br /&gt;
    &lt;br /&gt;
     if playerID &amp;lt; 0: return  # The server operator can be a potty-mouth if he wants&lt;br /&gt;
 &lt;br /&gt;
     for word in badWords:&lt;br /&gt;
         if msgText.find(word) == -1: continue&lt;br /&gt;
 &lt;br /&gt;
         playerName = bf2.playerManager.getPlayerByIndex(playerID).getName()&lt;br /&gt;
         host.rcon_invoke(&#039;game.sayall &amp;quot;Player %s kicked for using inappropriate language&amp;quot;&#039;&lt;br /&gt;
                          % playerName)&lt;br /&gt;
         host.rcon_invoke(&#039;pb_sv_kick &amp;quot;%s&amp;quot; %i &amp;quot;Using inappropriate language&amp;quot;&#039;&lt;br /&gt;
                          % (playerName, kickTime))&lt;br /&gt;
         print ( &#039;BadWords: Player %s kicked for saying &amp;quot;%s&amp;quot; at %s&#039;&lt;br /&gt;
                % (playerName, word, time.strftime(&amp;quot;%a %d-%b-%Y %H:%M&amp;quot;)) )&lt;br /&gt;
        &lt;br /&gt;
         break&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Discussion  ==&lt;br /&gt;
&lt;br /&gt;
There are lots of variations possible on this script: you could ban players instead of kicking them; you could warn them three times first, then kick them; you could save their profile ID or CD key for future action if they repeat their offense, etc. This script was written to be both simple and useful, but you could also extend the basic concept shown here to use regular expressions (to avoid kicking player &amp;quot;gilbert_grape&amp;quot;, for example, if the word &amp;quot;rape&amp;quot; was on your bad words list), at the expense of complicating both the script and the word list.&lt;br /&gt;
&lt;br /&gt;
It should also be pointed out that PunkBuster has a [http://www.evenbalance.com/publications/bf2-ad/index.htm#badname similar facility] for kicking players based on bad words in their player names; I&#039;ve found it to be a pain to configure, however, and it does nothing for chat messages, which is where the larger problem is. . . plus it leaves a lot of the &amp;quot;bad&amp;quot; words on your server console screen every time it loads its word list (not good for tours).&lt;/div&gt;</summary>
		<author><name>Pireax</name></author>
	</entry>
	<entry>
		<id>https://bf2tech.uturista.pt/index.php?title=Scripts:AutoShutdown&amp;diff=106</id>
		<title>Scripts:AutoShutdown</title>
		<link rel="alternate" type="text/html" href="https://bf2tech.uturista.pt/index.php?title=Scripts:AutoShutdown&amp;diff=106"/>
		<updated>2018-06-22T15:26:22Z</updated>

		<summary type="html">&lt;p&gt;Pireax: Created page with &amp;quot;== Introduction ==  I got tired of manually warning my users before shutdown, so I wrote this to automate the task for me. It warns players at intervals before shutting down....&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
I got tired of manually warning my users before shutdown, so I wrote this to automate the task for me. It warns players at intervals before shutting down. The warnings occur at 60, 30, 15, 10, 5, 4, 3, 2, 1 minutes before shutdown. This script needs serious work from someone who actually knows Python. I post it here in the hopes that people will improve on it (perhaps by moving the configuration variables into an easily-modified external file?)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Usage ==&lt;br /&gt;
&lt;br /&gt;
Copy/Paste this script into a text file. Save it as &amp;lt;code&amp;gt;autoshutdown.py&amp;lt;/code&amp;gt; in your &amp;lt;code&amp;gt;standard_admin&amp;lt;/code&amp;gt; folder. Modify your &amp;lt;code&amp;gt;__init__.py&amp;lt;/code&amp;gt; file to import and execute it.&lt;br /&gt;
&lt;br /&gt;
== Code ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
import datetime&lt;br /&gt;
import time&lt;br /&gt;
import host&lt;br /&gt;
import bf2&lt;br /&gt;
from bf2 import g_debug&lt;br /&gt;
&lt;br /&gt;
shutdownTime = &amp;quot;01:00&amp;quot; #use 24-hour time. Format should be &amp;quot;hh:mm&amp;quot;&lt;br /&gt;
quitOrPause = &amp;quot;pause&amp;quot; #options are &amp;quot;pause&amp;quot; (pause game but leave server running) or &amp;quot;quit&amp;quot; (kill the server)&lt;br /&gt;
&lt;br /&gt;
shutdownTimer = None&lt;br /&gt;
def init():&lt;br /&gt;
    global shutdownTime, shutdownTimer&lt;br /&gt;
    shutdownHour = int(time.strftime(&amp;quot;%H&amp;quot;,time.strptime(shutdownTime,&amp;quot;%H:%M&amp;quot;)))&lt;br /&gt;
    shutdownMinute = int(time.strftime(&amp;quot;%M&amp;quot;,time.strptime(shutdownTime,&amp;quot;%H:%M&amp;quot;)))&lt;br /&gt;
    today = datetime.datetime.now()&lt;br /&gt;
    shutdownTime = datetime.datetime(today.year, today.month, today.day, shutdownHour, shutdownMinute)&lt;br /&gt;
    if shutdownHour &amp;lt; today.hour:&lt;br /&gt;
        shutdownTime = datetime.datetime(today.year, today.month, today.day + 1, shutdownHour, shutdownMinute)&lt;br /&gt;
    shutdownTimer = bf2.Timer(checktime, 1, 1)&lt;br /&gt;
    shutdownTimer.setRecurring(60)&lt;br /&gt;
    host.rcon_invoke(&#039;echo &amp;quot;autoshutdown.py loaded&amp;quot;&#039;)&lt;br /&gt;
&lt;br /&gt;
def checktime(whatever):&lt;br /&gt;
    global shutdownTime&lt;br /&gt;
    global quitOrPause&lt;br /&gt;
   &lt;br /&gt;
    timeTilShutdown = shutdownTime - datetime.datetime.now()&lt;br /&gt;
    minsTilShutdown = int((timeTilShutdown.seconds / 60))&lt;br /&gt;
    host.rcon_invoke(&#039;echo &amp;quot;Debug: &#039; + str(minsTilShutdown) + &#039; minutes to shutdown.&amp;quot;&#039;)&lt;br /&gt;
    msg = None&lt;br /&gt;
    if minsTilShutdown == 60:&lt;br /&gt;
        msg = &#039;ADMIN: SERVER SHUTDOWN IN 60 MINUTES&#039;&lt;br /&gt;
    if minsTilShutdown == 30:&lt;br /&gt;
        msg = &#039;ADMIN: SERVER SHUTDOWN IN 30 MINUTES&#039;&lt;br /&gt;
    if minsTilShutdown == 15:&lt;br /&gt;
        msg = &#039;ADMIN: SERVER SHUTDOWN IN 15 MINUTES&#039;&lt;br /&gt;
    if minsTilShutdown == 10:&lt;br /&gt;
        msg = &#039;ADMIN: SERVER SHUTDOWN IN 10 MINUTES&#039;&lt;br /&gt;
    if minsTilShutdown == 5:&lt;br /&gt;
        msg = &#039;ADMIN: SERVER SHUTDOWN IN 5 MINUTES&#039;&lt;br /&gt;
    if 0 &amp;lt; minsTilShutdown &amp;lt; 5:&lt;br /&gt;
        msg = &#039;ADMIN: SERVER SHUTDOWN IN &#039; + str(minsTilShutdown) + &#039; MINUTE(S)&#039;&lt;br /&gt;
       &lt;br /&gt;
    if msg != None:&lt;br /&gt;
        adminMessage(msg)&lt;br /&gt;
       &lt;br /&gt;
    if minsTilShutdown &amp;lt;= 0:&lt;br /&gt;
        msg = &#039;ADMIN: SERVER WILL SHUTDOWN *NOW*&#039;&lt;br /&gt;
        adminMessage(msg)&lt;br /&gt;
        timestamp = time.strftime(&amp;quot;%Y-%m-%d, %I:%M:%S %p&amp;quot;,time.localtime())&lt;br /&gt;
        if quitOrPause == &amp;quot;quit&amp;quot;:&lt;br /&gt;
            if g_debug: print timestamp + &#039; -- Server halted.&#039;&lt;br /&gt;
            host.rcon_invoke(&#039;quit&#039;)&lt;br /&gt;
        if quitOrPause == &amp;quot;pause&amp;quot;:&lt;br /&gt;
            host.rcon_invoke(&#039;echo &amp;quot;&#039; + timestamp + &#039; -- Game paused.&amp;quot;&#039;)&lt;br /&gt;
            if g_debug: print timestamp + &#039; -- Game paused.&#039;&lt;br /&gt;
            host.rcon_invoke(&#039;gamelogic.togglepause&#039;)&lt;br /&gt;
&lt;br /&gt;
def adminMessage(msg):&lt;br /&gt;
    for i in range(1,26):&lt;br /&gt;
        host.rcon_invoke(&#039;game.sayAll &amp;quot;&#039; + msg + &#039;&amp;quot;&#039;)&lt;br /&gt;
    host.rcon_invoke(&#039;echo &amp;quot;&#039; + msg + &#039;&amp;quot;&#039;)&lt;br /&gt;
    if g_debug: print msg&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
: Greeze 07:50, 1 Jul 2005 (MDT)&lt;br /&gt;
: Greeze 04:13, 2 Jul 2005 (MDT) --&lt;br /&gt;
&lt;br /&gt;
::* Removed game status check (was creating multiple timer instances everytime the map changed); moved timer creation to init()&lt;br /&gt;
::* Slightly reordered message-sends in the checkTime function&lt;/div&gt;</summary>
		<author><name>Pireax</name></author>
	</entry>
	<entry>
		<id>https://bf2tech.uturista.pt/index.php?title=Scripts:Automatic_Announcements&amp;diff=105</id>
		<title>Scripts:Automatic Announcements</title>
		<link rel="alternate" type="text/html" href="https://bf2tech.uturista.pt/index.php?title=Scripts:Automatic_Announcements&amp;diff=105"/>
		<updated>2018-06-22T15:25:55Z</updated>

		<summary type="html">&lt;p&gt;Pireax: Created page with &amp;quot;Ever want to have an some announcement that is automatically periodically displayed on all players&amp;#039; screens? Here&amp;#039;s how to do it:  &amp;lt;pre&amp;gt;  import bf2  import bf2.Timer  import...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Ever want to have an some announcement that is automatically periodically displayed on all players&#039; screens? Here&#039;s how to do it:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 import bf2&lt;br /&gt;
 import bf2.Timer&lt;br /&gt;
 import host&lt;br /&gt;
 &lt;br /&gt;
 interval = 30   # Number of seconds between announcements&lt;br /&gt;
 message = &amp;quot;Your announcement message goes here&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 def onTimer(data):&lt;br /&gt;
     global message&lt;br /&gt;
     host.rcon_invoke(&#039;game.sayall &amp;quot;%s&amp;quot;&#039; % message)&lt;br /&gt;
 &lt;br /&gt;
 timer = bf2.Timer(onTimer, interval, 1)&lt;br /&gt;
 timer.setRecurring(interval)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To work, this script needs to be a module (in it&#039;s own file--for example, &amp;quot;&amp;lt;code&amp;gt;simpleAnnounce.py&amp;lt;/code&amp;gt;&amp;quot;) which is imported by one of the main BF2 modules or packages (bf2, the Admin module, or the bf2 mod); you can import it from any of these, but because of it&#039;s function, it probably makes the most sense to import it from the admin module.&lt;br /&gt;
&lt;br /&gt;
To do this, put simpleAnnounce.py into the directory &amp;lt;code&amp;gt;Battlefield 2 Server/Admin/standard_admin&amp;lt;/code&amp;gt;; then, in that same folder, edit the file &amp;lt;code&amp;gt;__init__.py&amp;lt;/code&amp;gt; and add the line&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt; import simpleAnnounce &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(it doesn&#039;t matter where you put this line inside &amp;lt;code&amp;gt;__init__.py&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
When the [[Admin_Module|Admin Module]] is initialized, it imports the &amp;lt;code&amp;gt;standard_admin&amp;lt;/code&amp;gt; package, which, because of the change you made, will now also import your &amp;lt;code&amp;gt;simpleAnnounce&amp;lt;/code&amp;gt; module. When a module is first imported the code in it is run, so &amp;lt;code&amp;gt;simpleAnnounce&amp;lt;/code&amp;gt; will create a [[Object_Reference#bf2.Timer|bf2.Timer]] object set to fire a [[Event_Reference#Timer_Events|TimerEvent]] every &amp;lt;code&amp;gt;interval&amp;lt;/code&amp;gt; seconds, with a callback to the &amp;lt;code&amp;gt;onTimer&amp;lt;/code&amp;gt; method. When &amp;lt;code&amp;gt;onTimer&amp;lt;/code&amp;gt; gets called every &amp;lt;code&amp;gt;interval&amp;lt;/code&amp;gt; seconds, it uses the &amp;lt;code&amp;gt;game.sayall&amp;lt;/code&amp;gt; server command to send your message to all players.&lt;br /&gt;
&lt;br /&gt;
This script is very basic--it should be easy to extend it to, for example, rotate one by one through a set of different messages, to read the messages it displays from a configuration file, etc.&lt;br /&gt;
&lt;br /&gt;
--Woody&lt;/div&gt;</summary>
		<author><name>Pireax</name></author>
	</entry>
	<entry>
		<id>https://bf2tech.uturista.pt/index.php?title=Scripts:dc_ass&amp;diff=104</id>
		<title>Scripts:dc ass</title>
		<link rel="alternate" type="text/html" href="https://bf2tech.uturista.pt/index.php?title=Scripts:dc_ass&amp;diff=104"/>
		<updated>2018-06-22T15:25:24Z</updated>

		<summary type="html">&lt;p&gt;Pireax: Created page with &amp;quot;__TOC__  == Introduction  ==  The DontCamp Administrative Support System is a completely server-side, python based admin system for Battlefield 2 that uses in-game chat comman...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== Introduction  ==&lt;br /&gt;
&lt;br /&gt;
The DontCamp Administrative Support System is a completely server-side, python based admin system for Battlefield 2 that uses in-game chat commands and cd keyhash authentication to provide easy to use and powerful administrative functions.&lt;br /&gt;
&lt;br /&gt;
Some of the better features of dc_ass are:&lt;br /&gt;
&lt;br /&gt;
* kicking by playername, partial playername, or player ID&lt;br /&gt;
* single command multiple kick options against clan tags or team number (only used for evil, I know)&lt;br /&gt;
* variable userlevels via a PB style power points system&lt;br /&gt;
* allows the general public to vote kick someone without the annoying prompts&lt;br /&gt;
* completely an in-game and fast admin system so you can spend your time playing&lt;br /&gt;
&lt;br /&gt;
== The code  ==&lt;br /&gt;
&lt;br /&gt;
=== dc_ass.py  ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
DontCamp.com Administrative Support System v. 1.2.1&lt;br /&gt;
written by: butter@dontcamp.com&lt;br /&gt;
 &lt;br /&gt;
Changelog:&lt;br /&gt;
    1.2 beta:&lt;br /&gt;
        * added support for multiple arguments in a chat command&lt;br /&gt;
        * no longer spews so much to the screen when someone is kicked&lt;br /&gt;
    1.1.1 beta:&lt;br /&gt;
        * playernames with prefixs can now issue commands&lt;br /&gt;
    1.1 beta:&lt;br /&gt;
        * added userlevels via a kick points system a la PB power users&lt;br /&gt;
        * added general public vote kicking&lt;br /&gt;
        * using keyhash rather than PB GUID for auth&lt;br /&gt;
        * moved to more OO codebase&lt;br /&gt;
        * extensions can now act on anything in the dc_ass object&lt;br /&gt;
 &lt;br /&gt;
Acknowledgements:&lt;br /&gt;
    Thanks to dst@dontcamp.com for significant coding contributions.&lt;br /&gt;
    Thanks to superwabbit@dontcamp.com for his conceptual contributions.&lt;br /&gt;
    Thanks to my brother for helping me with fundamental coding concepts.&lt;br /&gt;
    Thanks to the guy that was willing to sell me a T40 ThinkPad on eBay for&lt;br /&gt;
        that insanely low price!&lt;br /&gt;
    Dear God, thanks be to O&#039;Reilly!&lt;br /&gt;
    And a REALLY BIG thanks to Kevin Lockitt of blackbagops.com. This software&lt;br /&gt;
        is clearly a big stinkin&#039; rip off of BFSM, a program that did as much&lt;br /&gt;
        as anything to make DontCamp.com the successful gaming community that&lt;br /&gt;
        it is.&lt;br /&gt;
 &lt;br /&gt;
Purpose:&lt;br /&gt;
    To provide an in-game chat based admin system similar to Kevin Lockitt&#039;s&lt;br /&gt;
    Battlefield Server Manager while also providing a kick vote system&lt;br /&gt;
    similar to PunkBuster&#039;s Poweruser system.&lt;br /&gt;
 &lt;br /&gt;
Requirements:&lt;br /&gt;
    1. dc_debug.py - a common debugging function for all DontCamp.com BF2&lt;br /&gt;
       python level tools&lt;br /&gt;
    2. dc_ass_extensions.py - this file is currently required to exist but&lt;br /&gt;
       can be empty. See dc_ass_extensions Instructions.&lt;br /&gt;
    3. dc_ass_cmds.ini - the configuration file for all in-game admin commands&lt;br /&gt;
    4. power.dat - a list of your admins&#039; power levels and keyhashs&lt;br /&gt;
 &lt;br /&gt;
Known issues:&lt;br /&gt;
    1. writeToLogfile() is not currently tested or up-to-date and is therefore&lt;br /&gt;
        disabled.&lt;br /&gt;
    2. In general be very careful what you code in an extension. The BF2&lt;br /&gt;
       server may lag or crash when running poorly written extensions.&lt;br /&gt;
    3. dc_ass currently requires punkbuster to be enabled.&lt;br /&gt;
    4. There is almost no sanity checking for poorly configured INI files.&lt;br /&gt;
    5. Non permanent bans are not maintained between server restarts.&lt;br /&gt;
 &lt;br /&gt;
Setup:&lt;br /&gt;
    1. Drop dc_ass.py and dc_debug.py into the admin/standard_admin directory&lt;br /&gt;
       of your BF2 installation.&lt;br /&gt;
    2. Edit admin/standard_admin/__init__.py file to include these lines:&lt;br /&gt;
 &lt;br /&gt;
           import dc_ass&lt;br /&gt;
           dc_ass.init()&lt;br /&gt;
 &lt;br /&gt;
    3. Create an empty dc_ass_extensions.py file or populate it as per the&lt;br /&gt;
       dc_ass_extensions instructions below.&lt;br /&gt;
    4. Create a power.dat file as per the instructions below.&lt;br /&gt;
    5. Create / edit a dc_ass_cmds.ini file as per the instructions below.&lt;br /&gt;
 &lt;br /&gt;
power.dat Instructions:&lt;br /&gt;
    This file is simply a space delimited file with two values on each line&lt;br /&gt;
    that must exist in the admin/standard_admin directory. The first value is&lt;br /&gt;
    the power level assignment and the second value is the keyhash.&lt;br /&gt;
 &lt;br /&gt;
    Currently dc_ass is lacking some flexibily in that 10 kick points always&lt;br /&gt;
    causes a player to be kicked. Keep that in mind when assigning power&lt;br /&gt;
    levels.    The power level must be a positive integer but can otherwise be&lt;br /&gt;
    whatever you like.&lt;br /&gt;
 &lt;br /&gt;
    The keyhash for a user is a 32 digit hexidecimal number that be found when&lt;br /&gt;
    executing admin.listplayers in the console. I have written a dc_ass&lt;br /&gt;
    extensions that prints the keyhash for a user while in-game and I will like&lt;br /&gt;
    make that extensions available in the future. Please note that BF2&lt;br /&gt;
    keyhashes are NOT the same thing as PB GUID&#039;s.&lt;br /&gt;
 &lt;br /&gt;
    An example power.dat file:&lt;br /&gt;
 &lt;br /&gt;
    10 352a507c78da1dea6dd42a5867d3c2cc&lt;br /&gt;
    4 2365c8ef755723efc10b425fffb65ebe&lt;br /&gt;
 &lt;br /&gt;
    This examples shows that the player with the keyhash:&lt;br /&gt;
    352a507c78da1dea6dd42a5867d3c2cc can apply 10 kick points to each player&lt;br /&gt;
    and that the player with the keyhash: 2365c8ef755723efc10b425fffb65ebe can&lt;br /&gt;
    apply 4 kick points to each player.&lt;br /&gt;
   &lt;br /&gt;
    Since 10 kick points kicks a user, we can assume that any admin with a&lt;br /&gt;
    kick power of 10 is a full admin and therefore they can run &amp;quot;admin&amp;quot;&lt;br /&gt;
    commands. See the section on the dc_ass_cmds.ini file for more info.&lt;br /&gt;
   &lt;br /&gt;
dc_ass_cmds.ini Instructions:&lt;br /&gt;
    This file follows standard INI file formatting. Each section name is the&lt;br /&gt;
    name of a command that can be run from in-game text chat. Each section&lt;br /&gt;
    must have a &amp;quot;type&amp;quot; option. Supported types are:&lt;br /&gt;
        kick - a simple kick&lt;br /&gt;
        ban - a permanent ban (or possibly temporary)&lt;br /&gt;
        rcon - user defined rcon command execution&lt;br /&gt;
        extension - user defined python function execution&lt;br /&gt;
 &lt;br /&gt;
    Depending on the type, different options are required. Each type supports&lt;br /&gt;
    the &amp;quot;admin&amp;quot; option. When admin = 1, the user must have a kick power of 10&lt;br /&gt;
    to execute that command. When admin = 0, any user on your BF2 server is&lt;br /&gt;
    allowed to execute that command. The admin option is optional and defaults&lt;br /&gt;
    to 1.&lt;br /&gt;
 &lt;br /&gt;
    (* = required)&lt;br /&gt;
    Type: kick&lt;br /&gt;
    Options:&lt;br /&gt;
        *reason = (a non-delimited string contained the reason for this kick)&lt;br /&gt;
        length = (an integer representing how many minutes before the&lt;br /&gt;
            the offender will be allowed back into the game. If this option is&lt;br /&gt;
            missing, the default value will be 2.)&lt;br /&gt;
    Type: ban&lt;br /&gt;
    Options:&lt;br /&gt;
        *reason = (same as above)&lt;br /&gt;
        length = (same as above) (see known issue #5)&lt;br /&gt;
 &lt;br /&gt;
    Type: rcon&lt;br /&gt;
    Options:        &lt;br /&gt;
        *command = (a non-delimited string contained the rcon command you want&lt;br /&gt;
            to issue)&lt;br /&gt;
 &lt;br /&gt;
    Type: extension&lt;br /&gt;
    Options:&lt;br /&gt;
        *function = (the name of the function in dc_ass_extensions.py you want&lt;br /&gt;
            this command to run WITHOUT any (). See dc_ass_extensions&lt;br /&gt;
             Instructions.)&lt;br /&gt;
 &lt;br /&gt;
    An example dc_ass_cmds.ini file might look like this:&lt;br /&gt;
 &lt;br /&gt;
        [kfms]&lt;br /&gt;
        type = kick&lt;br /&gt;
        reason = for firing from a vehicle in/into an uncapturable spawn&lt;br /&gt;
        length = 5&lt;br /&gt;
 &lt;br /&gt;
        [brsc]&lt;br /&gt;
        type = ban&lt;br /&gt;
        reason = for a racist or slanderous comment&lt;br /&gt;
 &lt;br /&gt;
        [restart]&lt;br /&gt;
        type = rcon&lt;br /&gt;
        command = admin.restartmap&lt;br /&gt;
 &lt;br /&gt;
        [slap]&lt;br /&gt;
        type = extension&lt;br /&gt;
        function = slapPlayer&lt;br /&gt;
 &lt;br /&gt;
        [nextmap]&lt;br /&gt;
        type = extension&lt;br /&gt;
        function = sayNextMap&lt;br /&gt;
        admin = 0&lt;br /&gt;
 &lt;br /&gt;
    NOTE: Changes made to the dc_ass_cmds.ini file are in effect immediately&lt;br /&gt;
    and do not require a server restart.&lt;br /&gt;
 &lt;br /&gt;
dc_ass_extensions.py Instructions:&lt;br /&gt;
    The extensions provide a means to do more complex actions that cannot be&lt;br /&gt;
    achieved through a simple rcon command. This file works similarly to other&lt;br /&gt;
    python files inside the BF2 environment. It&#039;s simply a list of functions&lt;br /&gt;
    as well as the proper imports to provide the facility the functions&lt;br /&gt;
    require.&lt;br /&gt;
 &lt;br /&gt;
    NOTE: Each function that is run as an extension must accept one and only&lt;br /&gt;
    one parameter. That parameter will be the dc_ass admin object most noteably&lt;br /&gt;
    containing these properties:&lt;br /&gt;
   &lt;br /&gt;
    victim_id - a list of all integers of the victim IDs found via the&lt;br /&gt;
        parameter for this the command executed&lt;br /&gt;
       &lt;br /&gt;
    victim_tracker - a dictionary of all the people currently being tracked&lt;br /&gt;
        by dc_ass (in other words, people that have had kick points issued&lt;br /&gt;
        against    them). This is a multidemensional dictionary where the top&lt;br /&gt;
        level key is the player_id / slot number and value is another&lt;br /&gt;
        dictionary where the key is the keyhash of the issuer of the points and&lt;br /&gt;
        the value is the number of points issued by said issuer.&lt;br /&gt;
   &lt;br /&gt;
    issuer - an integer representing the player_id of the person that executed&lt;br /&gt;
        the current command.&lt;br /&gt;
       &lt;br /&gt;
    keyhash - a string that is the hexidecimal keyhash of the person that&lt;br /&gt;
        executed the current command.&lt;br /&gt;
 &lt;br /&gt;
    See http://dontcamp.com/code/ for an example dc_ass_extenions.py file.&lt;br /&gt;
 &lt;br /&gt;
    Note: Changes made to the dc_ass_extensions.py file are in effect&lt;br /&gt;
        immediately and do not require a server restart.&lt;br /&gt;
 &lt;br /&gt;
How to use all this once you&#039;ve got it setup:&lt;br /&gt;
    All commands are issued with in-game chat, NOT console commands. To my&lt;br /&gt;
    knowledge, these commands should work in any chat mode. Each command MUST&lt;br /&gt;
    be prefixed with an ! and optionally suffixed with a space followed by a&lt;br /&gt;
    case insensitive playername, partial playername, or a . followed by a&lt;br /&gt;
    player number. Additionally, you may prefex an @ in front of a case&lt;br /&gt;
    insensitive string to execute an action against all players containing&lt;br /&gt;
    that string in their playername. You may also use a % followed by a team&lt;br /&gt;
    number to execute a command against an entire team.&lt;br /&gt;
 &lt;br /&gt;
    Using our previous example INI file and given that the server has two&lt;br /&gt;
    players on it: Butter (in slot 0) and MuttDog (in slot 1) here&#039;s how the&lt;br /&gt;
    following commands would react...&lt;br /&gt;
 &lt;br /&gt;
        !kfms&lt;br /&gt;
            [ Whenever no parameter for a victim is given, dc_ass will&lt;br /&gt;
              assume the player ID of the admin issuing the command. In this&lt;br /&gt;
              case the admin will be kicked for 5 minutes for firing into&lt;br /&gt;
              a main spawn. ]&lt;br /&gt;
 &lt;br /&gt;
        !kfms .0&lt;br /&gt;
            [ This will kick Butter for 5 minutes for firing into a main spawn&lt;br /&gt;
              because butter is player number 0 / in slot 0. ]&lt;br /&gt;
 &lt;br /&gt;
        !kfms butter&lt;br /&gt;
            [ This will also kick Butter because butter matches Butter in our&lt;br /&gt;
              case insensitive string comparison. ]&lt;br /&gt;
 &lt;br /&gt;
        !kfms ter&lt;br /&gt;
            [ This will also kick Butter because ter is a string match in&lt;br /&gt;
              Butter&#039;s name and ONLY in Butter&#039;s name. ]&lt;br /&gt;
 &lt;br /&gt;
        !kfms utt&lt;br /&gt;
            [ This will kick no one but print a global message in green at the&lt;br /&gt;
              top left of the screen that utt is ambiguous. ]&lt;br /&gt;
 &lt;br /&gt;
        !kfms dst&lt;br /&gt;
            [ This will kick no one and print a global message saying &amp;quot;Could&lt;br /&gt;
              not find ID for dst&amp;quot;. ]&lt;br /&gt;
 &lt;br /&gt;
        !kfms @t&lt;br /&gt;
            [ This will kick both dst and butter as they both have a t in their&lt;br /&gt;
              their playername. ]&lt;br /&gt;
 &lt;br /&gt;
        !kfms @T&lt;br /&gt;
            [ This will still kick both dst and butter because our text search&lt;br /&gt;
              is case insensitive. ]&lt;br /&gt;
 &lt;br /&gt;
        !kfms %2&lt;br /&gt;
            [ This will kick everyone on team 2. ]&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
import bf2&lt;br /&gt;
import host&lt;br /&gt;
import re&lt;br /&gt;
import ConfigParser&lt;br /&gt;
import time&lt;br /&gt;
from dc_debug import decho&lt;br /&gt;
from dc_debug import showLevel&lt;br /&gt;
import dc_ass_extensions&lt;br /&gt;
 &lt;br /&gt;
class ass:&lt;br /&gt;
    # some init vars&lt;br /&gt;
    victim_tracker = {}&lt;br /&gt;
    admin_level = 10&lt;br /&gt;
    default_weight = 2&lt;br /&gt;
    kick_threshold = 10&lt;br /&gt;
 &lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        _getPlayerList(): returns a dictionary of players currently playing&lt;br /&gt;
        where the key is their player player_id/index and the value is list&lt;br /&gt;
        containing their playername, IP, outbound port, and CD-key hash.&lt;br /&gt;
        Thanks to Woody for doing all the hard work on this one.&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    def _getPlayerList(self):&lt;br /&gt;
        rawData = host.rcon_invoke( &#039;admin.listplayers&#039; )&lt;br /&gt;
        # this patern is for line 0 of the output for each player&lt;br /&gt;
        # pattern1 = re.compile(r&#039;&#039;&#039;^Id:\ +(\d+)\ -\ (\S+)\ is\ remote\ ip:\ (\d+\.\d+\.\d+\.\d+):(\d+)&#039;&#039;&#039;, re.VERBOSE)&lt;br /&gt;
        pattern1 = re.compile(r&#039;&#039;&#039;^Id:\ +(\d+)\ -\ (.*?)\ is\ remote\ ip:\ (\d+\.\d+\.\d+\.\d+):(\d+)&#039;&#039;&#039;, re.VERBOSE)&lt;br /&gt;
        # this patern is for line 1 of the output for each player&lt;br /&gt;
        pattern2 = re.compile(r&#039;&#039;&#039;(?:.*hash:\ (\w{32}))?&#039;&#039;&#039;, re.VERBOSE)&lt;br /&gt;
        players = {}&lt;br /&gt;
       &lt;br /&gt;
        i = 0&lt;br /&gt;
        for line in rawData.split(&amp;quot;\n&amp;quot;):&lt;br /&gt;
            # if we&#039;re looking at a &amp;quot;line 0&amp;quot;&lt;br /&gt;
            if i == 0:&lt;br /&gt;
                matches = pattern1.findall(line)&lt;br /&gt;
                if len(matches) != 0:&lt;br /&gt;
                    p_id = int(matches[0][0])&lt;br /&gt;
                    players[p_id] = []&lt;br /&gt;
                    players[p_id].append(matches[0][1])&lt;br /&gt;
                    players[p_id].append(matches[0][2])&lt;br /&gt;
                    players[p_id].append(matches[0][3])&lt;br /&gt;
 &lt;br /&gt;
            # if we&#039;re looking at a &amp;quot;line 1&amp;quot;&lt;br /&gt;
            elif i == 1:&lt;br /&gt;
                matches = pattern2.findall(line)&lt;br /&gt;
                players[p_id].append(matches[0])&lt;br /&gt;
 &lt;br /&gt;
            # flop the value of the iter&lt;br /&gt;
            i ^= 1&lt;br /&gt;
       &lt;br /&gt;
        return players&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        _getWeight(): finds the admin level of the user at index&lt;br /&gt;
        returns true on success, false on failure (the true case being that a user is found at index)&lt;br /&gt;
        assigns string self.keyhash as the keyhash of the user at index&lt;br /&gt;
        assigns int self.user_weight as the admin level of the user at index&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    def _getWeight(self, index):&lt;br /&gt;
        return_value = False&lt;br /&gt;
        players = self._getPlayerList()&lt;br /&gt;
        self.user_weight = self.default_weight&lt;br /&gt;
 &lt;br /&gt;
        if players.has_key(index):&lt;br /&gt;
            return_value = True&lt;br /&gt;
            self.keyhash = players[index][3]&lt;br /&gt;
            # assigns the default weight in case this user is not found in the pbpower.dat file&lt;br /&gt;
            decho( &amp;quot;dc_ass: Attempting to authenticate keyhash: %s&amp;quot; % self.keyhash, 5 )&lt;br /&gt;
 &lt;br /&gt;
            # just in case there is no pbpower.dat file&lt;br /&gt;
            try:&lt;br /&gt;
                for line in open(&#039;admin/standard_admin/power.dat&#039;, &#039;r&#039;):&lt;br /&gt;
                    if self.keyhash == line.split(&#039; &#039;)[1].strip():&lt;br /&gt;
                        self.user_weight = int(line.split(&#039; &#039;)[0].strip())&lt;br /&gt;
                        decho( &amp;quot;dc_ass: %s is level %d in power.dat!&amp;quot; % (self.keyhash, self.user_weight), 5 )&lt;br /&gt;
                        break&lt;br /&gt;
 &lt;br /&gt;
            except IOError:&lt;br /&gt;
                decho( &amp;quot;dc_ass: unable to open pb/pbpower.dat file&amp;quot;, 5 )&lt;br /&gt;
 &lt;br /&gt;
        return return_value&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        _getVictimId(): finds all victims from the in-game chat command parameter&lt;br /&gt;
        returns true on success and false on failure (the failure case is not being able to determine with certainly which victims the command is for)&lt;br /&gt;
        assigns list self.victim_id&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    def _getVictimId(self, parameter):&lt;br /&gt;
        # returns true/false on success/failure and assigns self.victim_id if possible&lt;br /&gt;
        # self.victim_id is a list of all victims found&lt;br /&gt;
        # sorry for the silly parameter name, but it does make sense in this case.&lt;br /&gt;
 &lt;br /&gt;
        self.victim_id = []&lt;br /&gt;
        result = False # default value for result&lt;br /&gt;
        decho(&amp;quot;dc_ass: Attempting to find victim ID...&amp;quot;, 5)&lt;br /&gt;
       &lt;br /&gt;
        # if the parameter is the player number&lt;br /&gt;
        if parameter[0:1] == &amp;quot;.&amp;quot;:&lt;br /&gt;
            id = int(parameter[1:])&lt;br /&gt;
   &lt;br /&gt;
            for p in bf2.playerManager.getPlayers():&lt;br /&gt;
                if p.index == id:&lt;br /&gt;
                    self.victim_id = [id]&lt;br /&gt;
                    decho( &amp;quot;dc_ass: parameter was an int, and id = %d&amp;quot; % self.victim_id[0], 5 )&lt;br /&gt;
                    result = True   &lt;br /&gt;
                    break&lt;br /&gt;
 &lt;br /&gt;
            if not result:&lt;br /&gt;
                decho( &amp;quot;dc_ass: (ERROR) no player found with ID: %d&amp;quot; % id, 1 )&lt;br /&gt;
           &lt;br /&gt;
        # if the parameter is a wildcard / clantag&lt;br /&gt;
        elif parameter[0:1] == &amp;quot;@&amp;quot;:&lt;br /&gt;
            decho( &amp;quot;dc_ass: finding ALL matching players with parameter...&amp;quot;, 5 )&lt;br /&gt;
            decho( &amp;quot;dc_ass: parameter was NOT an int&amp;quot;, 5 )&lt;br /&gt;
 &lt;br /&gt;
            # for all players connected...&lt;br /&gt;
            for p in bf2.playerManager.getPlayers():&lt;br /&gt;
                decho( &amp;quot;dc_ass: checking player: %s&amp;quot; % p.getName(), 5 )&lt;br /&gt;
                # if we find a name that loosely matches...&lt;br /&gt;
                if p.getName().lower().find( parameter[1:].lower() ) != -1:&lt;br /&gt;
                    decho( &amp;quot;dc_ass: %s loosely matches %s&amp;quot; % ( parameter[1:], p.getName() ), 5 )&lt;br /&gt;
                    self.victim_id.append(p.index)&lt;br /&gt;
                    result = True&lt;br /&gt;
 &lt;br /&gt;
            if result:&lt;br /&gt;
                decho( &amp;quot;dc_ass: Victim ID(s) found @ %r&amp;quot; % self.victim_id, 5 )&lt;br /&gt;
            else:&lt;br /&gt;
                decho( &amp;quot;dc_ass: (ERROR) no players found with %s in their name&amp;quot; % parameter[1:], 1 )&lt;br /&gt;
       &lt;br /&gt;
        # if the parameter is a team number&lt;br /&gt;
        elif parameter[0:1] == &amp;quot;%&amp;quot;:&lt;br /&gt;
            decho( &amp;quot;dc_ass: finding ALL matching players on team matching paramenter...&amp;quot;, 5 )&lt;br /&gt;
           &lt;br /&gt;
            # for all players connected...&lt;br /&gt;
            for p in bf2.playerManager.getPlayers():&lt;br /&gt;
                decho( &amp;quot;dc_ass: checking player: %s&amp;quot; % p.getName(), 5 )&lt;br /&gt;
                # if we find a player on the team supplied&lt;br /&gt;
                if p.getTeam() == int(parameter[1:]):&lt;br /&gt;
                    decho( &amp;quot;dc_ass: %s is on team %s&amp;quot; % ( p.getName(), p.getTeam() ), 5 )&lt;br /&gt;
                    self.victim_id.append(p.index)&lt;br /&gt;
                    result = True               &lt;br /&gt;
 &lt;br /&gt;
            if result:&lt;br /&gt;
                decho( &amp;quot;dc_ass: Victim ID(s) found @ %r&amp;quot; % self.victim_id, 5 )&lt;br /&gt;
            else:&lt;br /&gt;
                decho( &amp;quot;dc_ass: (ERROR) there seems to be no one on team %s&amp;quot; % parameter[1:], 1 )&lt;br /&gt;
                   &lt;br /&gt;
        # if the parameter is a playername or partial playername&lt;br /&gt;
        else:&lt;br /&gt;
            id = -1&lt;br /&gt;
            decho(&amp;quot;dc_ass: parameter was NOT an int&amp;quot;, 5)&lt;br /&gt;
            # for all players connected...&lt;br /&gt;
            for p in bf2.playerManager.getPlayers():&lt;br /&gt;
                decho( &amp;quot;dc_ass: checking player: %s&amp;quot; % p.getName(), 5 )&lt;br /&gt;
                # if we find a name that loosely matches...&lt;br /&gt;
                if p.getName().lower().find( parameter.lower() ) != -1:&lt;br /&gt;
                    decho( &amp;quot;dc_ass: %s loosely matches %s&amp;quot; % ( parameter, p.getName() ), 5 )&lt;br /&gt;
                    # if this is the first victim we&#039;ve found...&lt;br /&gt;
                    if id == -1:&lt;br /&gt;
                        decho(&amp;quot;dc_ass: found %s in %s&amp;quot; % ( parameter, p.getName() ), 5)&lt;br /&gt;
                        id = [int(p.index)]&lt;br /&gt;
                        result = True&lt;br /&gt;
                    # if we&#039;ve gotten another possible match...&lt;br /&gt;
                    else:&lt;br /&gt;
                        result = False&lt;br /&gt;
                        break&lt;br /&gt;
 &lt;br /&gt;
            if result:&lt;br /&gt;
                self.victim_id = id&lt;br /&gt;
                decho( &amp;quot;dc_ass: Victim ID found @ %d&amp;quot; % self.victim_id[0], 5 )&lt;br /&gt;
            else:&lt;br /&gt;
                decho( &amp;quot;dc_ass: %s is ambiguous.&amp;quot; % parameter, 1 )&lt;br /&gt;
 &lt;br /&gt;
        return result&lt;br /&gt;
 &lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    def writeLogFile(self, victim_id, admin_id, type, reason, length):&lt;br /&gt;
        v = bf2.PlayerManager.Player(victim_id)&lt;br /&gt;
        a = bf2.PlayerManager.Player(admin_id)&lt;br /&gt;
        decho(&amp;quot;\&amp;quot;%s\&amp;quot;,%s,%d,%s,%d,%s,%s,%d,%s\n&amp;quot; % (v.getName(), v.getAddress(), v.getProfileId(), a.getName(), int(time.time()), bf2.gameLogic.getMapName(), type, reason, length * 60), 5)&lt;br /&gt;
 &lt;br /&gt;
        fo = open(&#039;admin/standard_admin/adminlog.csv&#039;, &#039;a&#039;)&lt;br /&gt;
        # v.name, v.ip, v.profileId, a.name, timestamp, map, type, length, reason&lt;br /&gt;
        fo.write(&amp;quot;\&amp;quot;%s\&amp;quot;,%s,%d,%s,%d,%s,%s,%d,%s\n&amp;quot; % (v.getName(), v.getAddress(), v.getProfileId(), a.getName(), int(time.time()), bf2.gameLogic.getMapName(), type, reason, length * 60))&lt;br /&gt;
        fo.close()&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        _stripPrefix(): removes context prefixes from a chati lines and returns the trimmed chat line&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    def _stripPrefix(self, text):&lt;br /&gt;
        text = text.replace( &amp;quot;HUD_TEXT_CHAT_TEAM&amp;quot;, &amp;quot;&amp;quot; )&lt;br /&gt;
        text = text.replace( &amp;quot;HUD_TEXT_CHAT_SQUAD&amp;quot;, &amp;quot;&amp;quot; )&lt;br /&gt;
        text = text.replace( &amp;quot;HUD_CHAT_DEADPREFIX&amp;quot;, &amp;quot;&amp;quot; )&lt;br /&gt;
        text = text.replace( &amp;quot;*\xA71DEAD\xA70*&amp;quot;, &amp;quot;&amp;quot; )&lt;br /&gt;
 &lt;br /&gt;
        return text.strip()&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
    def addPoints(self):&lt;br /&gt;
        # add entries in the victim_tracker foreach victim&lt;br /&gt;
        for v_id in self.victim_id:&lt;br /&gt;
            # check to see if we&#039;re already tracking the joker&lt;br /&gt;
            if self.victim_tracker.has_key(v_id):&lt;br /&gt;
                decho( &amp;quot;dc_ass: already tracking %d&amp;quot; % v_id, 5 )&lt;br /&gt;
                # check to see if this admin has already applied their weight to the victim&lt;br /&gt;
                if not self.victim_tracker[v_id].has_key(self.keyhash):&lt;br /&gt;
                    self.victim_tracker[v_id][self.keyhash] = self.user_weight&lt;br /&gt;
                    # added this conditional to make it a bit less noisy when someone is just kicked with one action&lt;br /&gt;
                    if self.user_weight &amp;lt; self.kick_threshold:&lt;br /&gt;
                        decho( &amp;quot;dc_ass: applied %d points from %s to player %d&amp;quot; % (self.user_weight, self.keyhash, v_id), 5 )&lt;br /&gt;
                # this elif was really added to deal with an extension used at DontCamp.com but it makes sense to have anyway&lt;br /&gt;
                elif self.user_weight == self.kick_threshold:&lt;br /&gt;
                    self.victim_tracker[v_id][self.keyhash] = self.user_weight&lt;br /&gt;
                else:&lt;br /&gt;
                    decho( &amp;quot;dc_ass: %s has already applied their points to %s&amp;quot; % (bf2.PlayerManager.Player(self.issuer).getName(), bf2.PlayerManager.Player(v_id).getName()), 1 )&lt;br /&gt;
            else:&lt;br /&gt;
                self.victim_tracker[v_id] = {}&lt;br /&gt;
                decho( &amp;quot;dc_ass: now tracking player: %d&amp;quot; % v_id, 5 )&lt;br /&gt;
                self.victim_tracker[v_id][self.keyhash] = self.user_weight&lt;br /&gt;
                decho( &amp;quot;dc_ass: applied %d points from %s to player %d&amp;quot; % (self.user_weight, self.keyhash, v_id), 5 )&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
    def checkPoints(self):&lt;br /&gt;
        for index, tracking in self.victim_tracker.iteritems():&lt;br /&gt;
            # reset total_points for this victim&lt;br /&gt;
            total_points = 0&lt;br /&gt;
 &lt;br /&gt;
            # added up all the points being applied to this victim&lt;br /&gt;
            for unused_key, points in tracking.iteritems():&lt;br /&gt;
                total_points += points   &lt;br /&gt;
               &lt;br /&gt;
            if index in self.victim_id:&lt;br /&gt;
                decho( &amp;quot;dc_ass: %s now has %d of %d kick points&amp;quot; % (bf2.PlayerManager.Player(index).getName(), total_points, self.kick_threshold), 1 )&lt;br /&gt;
 &lt;br /&gt;
            if total_points &amp;gt;= self.kick_threshold:&lt;br /&gt;
                self.reason += &amp;quot; - see dontcamp.com/forums for discussion&amp;quot;&lt;br /&gt;
                # issue the kick command&lt;br /&gt;
                decho( &amp;quot;dc_ass: Kicking player &#039;%s&#039; (%d) %s&amp;quot; % (bf2.PlayerManager.Player(index).getName(), index, self.reason), 1 )&lt;br /&gt;
                unused = host.rcon_invoke(&#039;pb_sv_kick %d %d %s&#039; % (index + 1, self.length, self.reason) )&lt;br /&gt;
 &lt;br /&gt;
    # it might be helpful to create a new object to pass to extensions that&lt;br /&gt;
    # has a reference to the admin object. In that new object, that I hope&lt;br /&gt;
    # would only exist during the execution of a command, things like the&lt;br /&gt;
    # issuer and keyhash properties could be assigned.&lt;br /&gt;
    def onChatMessage(self, player_id, text, channel, flags):&lt;br /&gt;
        self.issuer = player_id&lt;br /&gt;
        # pull the potential prefix off the text line&lt;br /&gt;
        text = self._stripPrefix(text)&lt;br /&gt;
       &lt;br /&gt;
        # unless the first character is ! don&#039;t do anything&lt;br /&gt;
        if text[0:1] == &amp;quot;!&amp;quot;:&lt;br /&gt;
            decho( &amp;quot;dc_ass: the first character of %s was !&amp;quot; % text, 5 )&lt;br /&gt;
 &lt;br /&gt;
            # As BF2 playernames cannot contain spaces except what is printed&lt;br /&gt;
            # between the prefix and the name, it is probably safe to assume&lt;br /&gt;
            # that we don&#039;t need to accept spaces in playernames for this&lt;br /&gt;
            # parameter. Therefore, I could use the space as a separator&lt;br /&gt;
            # between the victim name and another command parameter, like&lt;br /&gt;
            # a custom reason.&lt;br /&gt;
 &lt;br /&gt;
            # grab the parts of the chatline I need with a REGEX&lt;br /&gt;
            pattern = re.compile(r&#039;!(\w*) ?(\S*) ?(.*)&#039;)&lt;br /&gt;
            matches = pattern.findall(text)&lt;br /&gt;
            command = matches[0][0]&lt;br /&gt;
            # set an arguments property for future use or for extensions&lt;br /&gt;
            self.arguments = matches[0][2]&lt;br /&gt;
            decho( &amp;quot;dc_ass: command = %s&amp;quot; % command, 5 ) &lt;br /&gt;
 &lt;br /&gt;
            # in case the command doesn&#039;t require a victim parameter...&lt;br /&gt;
            if matches[0][1] != &amp;quot;&amp;quot;:&lt;br /&gt;
                parameter = matches[0][1]&lt;br /&gt;
                decho( &amp;quot;dc_ass: parameter = %s&amp;quot; % parameter, 5 )&lt;br /&gt;
            else:&lt;br /&gt;
                parameter = None&lt;br /&gt;
                decho( &amp;quot;dc_ass: no parameter given&amp;quot;, 5 )&lt;br /&gt;
 &lt;br /&gt;
            try: # read in the commands INI file&lt;br /&gt;
                self.config = ConfigParser.ConfigParser()&lt;br /&gt;
                self.config.read(&#039;admin/standard_admin/dc_ass_cmds.ini&#039;)&lt;br /&gt;
 &lt;br /&gt;
                # is this a defined command in the INI file&lt;br /&gt;
                if command in self.config.sections():&lt;br /&gt;
                    decho( &amp;quot;dc_ass: Command found in INI file!&amp;quot;, 5 )&lt;br /&gt;
                    # define/declare some vars for this admin event (I really wouldn&#039;t need to do this if I know how to check if a var is defined or even exists&lt;br /&gt;
                    type = &amp;quot;&amp;quot;&lt;br /&gt;
                    # these values will be members of the object because they may be needed in an extension&lt;br /&gt;
                    self.length = 2 # the default length for a kick&lt;br /&gt;
                    self.reason = &amp;quot;&amp;quot;&lt;br /&gt;
                    admin = 1 # this makes all commands default to requiring admin privs&lt;br /&gt;
 &lt;br /&gt;
                    # get all possible options&lt;br /&gt;
                    # I could add sanity checks in here for poorly formated lines in the INI file&lt;br /&gt;
                    for option in self.config.options(command):&lt;br /&gt;
                        if option == &amp;quot;type&amp;quot;:&lt;br /&gt;
                            type = self.config.get(command, option).strip()&lt;br /&gt;
                        elif option == &amp;quot;reason&amp;quot;:&lt;br /&gt;
                            self.reason = self.config.get(command, option).strip()&lt;br /&gt;
                        elif option == &amp;quot;length&amp;quot;:&lt;br /&gt;
                            self.length = int(self.config.get(command, option))&lt;br /&gt;
                        elif option == &amp;quot;command&amp;quot;:&lt;br /&gt;
                            rcon_string = self.config.get(command, option).strip()&lt;br /&gt;
                        elif option == &amp;quot;admin&amp;quot;:&lt;br /&gt;
                            admin = int(self.config.get(command, option))&lt;br /&gt;
                        elif option == &amp;quot;function&amp;quot;:&lt;br /&gt;
                            function = self.config.get(command, option).strip()&lt;br /&gt;
 &lt;br /&gt;
                    # make sure we have a type&lt;br /&gt;
                    if type == &amp;quot;&amp;quot;:&lt;br /&gt;
                        decho( &amp;quot;dc_ass: (ERROR) No type value for %s in dc_ass_cmds.ini file!&amp;quot; % command, 1 )&lt;br /&gt;
                   &lt;br /&gt;
                    # good, we&#039;re all set&lt;br /&gt;
                    else:&lt;br /&gt;
                        decho( &amp;quot;dc_ass: type: %s&amp;quot; % type, 5 )&lt;br /&gt;
 &lt;br /&gt;
                        # to get their keyhash and admin level&lt;br /&gt;
                        if self._getWeight(player_id):&lt;br /&gt;
 &lt;br /&gt;
                            # see if we can/need to get a victim ID to move forward&lt;br /&gt;
                            if ( parameter != None and self._getVictimId(parameter) ) or parameter == None:&lt;br /&gt;
 &lt;br /&gt;
                                # for non-perma bans, change type to kick_ban - this will be useful when we start to log this stuff&lt;br /&gt;
                                if type == &amp;quot;ban&amp;quot; and self.length != &amp;quot;&amp;quot;:&lt;br /&gt;
                                    decho( &amp;quot;dc_ass: Length value given for ban. Converting type to kick_ban.&amp;quot;, 5 )&lt;br /&gt;
                                    type = &amp;quot;kick_ban&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
                                # if no parameter was given, make the command reflect on the issuer&lt;br /&gt;
                                if parameter == None:&lt;br /&gt;
                                    decho( &amp;quot;dc_ass: No parameter given... assigning victim_id to issuer.&amp;quot;, 5 )&lt;br /&gt;
                                    self.victim_id = [player_id]&lt;br /&gt;
 &lt;br /&gt;
                                if ( admin and self.user_weight == self.admin_level ) or not admin:&lt;br /&gt;
 &lt;br /&gt;
                                    # the main switch like section that gets the shit done (if only I had switches)&lt;br /&gt;
                                    # Are reasons optional in these PB kicks/bans? If so, I guess I don&#039;t need to worry about sanity checking them&lt;br /&gt;
 &lt;br /&gt;
                                    if type == &amp;quot;kick&amp;quot; or type == &amp;quot;kick_ban&amp;quot;:&lt;br /&gt;
                                        self.addPoints()&lt;br /&gt;
                                        self.checkPoints()&lt;br /&gt;
 &lt;br /&gt;
                                    elif type == &amp;quot;ban&amp;quot;:&lt;br /&gt;
                                        for v_id in self.victim_id:&lt;br /&gt;
                                            decho( &amp;quot;dc_ass: Banning player &#039;%s&#039; (%d) %s&amp;quot; % (bf2.PlayerManager.Player(v_id).getName(), v_id, self.reason), 1 )&lt;br /&gt;
                                            unused = host.rcon_invoke( &#039;pb_sv_ban %d %s&#039; % (v_id + 1, self.reason) )&lt;br /&gt;
           &lt;br /&gt;
                                    elif type == &amp;quot;rcon&amp;quot;:&lt;br /&gt;
                                        decho( &amp;quot;dc_ass: Running rcon command: %s&amp;quot; % rcon_string, 2 )&lt;br /&gt;
                                        unused = host.rcon_invoke( rcon_string )&lt;br /&gt;
           &lt;br /&gt;
                                    elif type == &amp;quot;extension&amp;quot;:&lt;br /&gt;
                                        reload( dc_ass_extensions )&lt;br /&gt;
                                        if function in dc_ass_extensions.__dict__:&lt;br /&gt;
                                            decho( &amp;quot;dc_ass: executing %s() extension&amp;quot; % function, 2 )&lt;br /&gt;
                                            # send the entire object to the extensions&lt;br /&gt;
                                            exec( &amp;quot;dc_ass_extensions.%s(%s)&amp;quot; % (function, &amp;quot;self&amp;quot;) )&lt;br /&gt;
                                        else:&lt;br /&gt;
                                            decho( &amp;quot;dc_ass: %s() extension not found.&amp;quot; % function, 2 )&lt;br /&gt;
 &lt;br /&gt;
                                    else:&lt;br /&gt;
                                        decho( &amp;quot;dc_ass: No such type: %s&amp;quot; % type, 1 )&lt;br /&gt;
 &lt;br /&gt;
                                else:&lt;br /&gt;
                                    decho ( &amp;quot;dc_ass: User in slot %d is not authorized for the requested action&amp;quot; % player_id, 1 )&lt;br /&gt;
 &lt;br /&gt;
                            else:&lt;br /&gt;
                                decho( &amp;quot;dc_ass: Victim ID not findable given the parameter&amp;quot;, 2 )&lt;br /&gt;
 &lt;br /&gt;
                        else:&lt;br /&gt;
                            decho( &amp;quot;dc_ass: ERROR failed to get keyhash for player: %d&amp;quot; % player_id, 1 )&lt;br /&gt;
                               &lt;br /&gt;
                else: # end of is command in INI file conditional&lt;br /&gt;
                    decho( &amp;quot;dc_ass: (ERROR) %s command not found!&amp;quot; % command, 1 )&lt;br /&gt;
       &lt;br /&gt;
            except IOError:&lt;br /&gt;
                print &amp;quot;dc_ass: (FATAL ERROR) could not open one or more required files: (admin_profile_ids.csv | dc_ass_cmds.ini)&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
        else: # a debug line just so I can see all the chat if I need to&lt;br /&gt;
            decho( &amp;quot;dc_ass: player %d: %s&amp;quot; % (player_id, text), 5 )&lt;br /&gt;
           &lt;br /&gt;
    def onPlayerDisconnect(self, p):&lt;br /&gt;
        # if they disconnect, which might have happened if they were kicked, drop them from the tracker, if they&#039;re even in it&lt;br /&gt;
        if self.victim_tracker.has_key(p.index):&lt;br /&gt;
            del(self.victim_tracker[p.index])&lt;br /&gt;
            decho( &amp;quot;dc_ass: player %d disconnected and no longer tracked&amp;quot; % p.index, 2 )&lt;br /&gt;
 &lt;br /&gt;
admin = ass()&lt;br /&gt;
 &lt;br /&gt;
def init():&lt;br /&gt;
    decho(&#039;dc_ass: initializing DontCamp.com Admin Support System&#039;, 2)&lt;br /&gt;
    host.registerHandler(&#039;ChatMessage&#039;, admin.onChatMessage, 1)&lt;br /&gt;
    host.registerHandler(&#039;PlayerDisconnect&#039;, admin.onPlayerDisconnect, 1)&lt;br /&gt;
    showLevel()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The source is downloadable from [http://dontcamp.com/code/?file=dc_ass.py&amp;amp;release=1 here].&lt;br /&gt;
&lt;br /&gt;
=== Change Log ===&lt;br /&gt;
&lt;br /&gt;
==== 1.2 beta ====&lt;br /&gt;
* added support for multiple arguments in a chat command&lt;br /&gt;
* no longer spews so much to the screen when someone is kicked&lt;br /&gt;
&lt;br /&gt;
==== 1.1.1 beta ====&lt;br /&gt;
* playernames with prefixs can now issue commands&lt;br /&gt;
&lt;br /&gt;
==== 1.1 beta ====&lt;br /&gt;
* added userlevels via a kick points system a la PB power users&lt;br /&gt;
* added general public vote kicking&lt;br /&gt;
* using keyhash rather than PB GUID for auth        * moved to more OO codebase&lt;br /&gt;
* extensions can now act on anything in the dc_ass object&lt;br /&gt;
&lt;br /&gt;
=== dc_debug.py  ===&lt;br /&gt;
&lt;br /&gt;
dc_debug.py is required for nearly all DontCamp BF2 python code. It manages the debuging and logging output of our software.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
DontCamp.com Common Debugging Function&lt;br /&gt;
written by: butter@dontcamp.com&lt;br /&gt;
Revision: $Revision: 1.11 $&lt;br /&gt;
 &lt;br /&gt;
Purpose:&lt;br /&gt;
    To provide a central way for all DontCamp BF2 python code to output&lt;br /&gt;
    debugging and informational text.&lt;br /&gt;
 &lt;br /&gt;
Setup: (defaults should work well)&lt;br /&gt;
 &lt;br /&gt;
    1. Create a admin/standard_admin/dc_debug.level file and put the debug&lt;br /&gt;
       level you want in the first character of the first line of said file.&lt;br /&gt;
       Valid levels are 1-5.&lt;br /&gt;
    2. Set log_to_file to either False or True if you want a seperate dc_debug&lt;br /&gt;
       log file for all DontCamp BF2 python code debug output.&lt;br /&gt;
    3. Set log_filename to whatever filename and path you like (relative to&lt;br /&gt;
       your BF2 home directory). This is only necessary if log_to_file is set&lt;br /&gt;
       to True.&lt;br /&gt;
    4. Set log_to_stdout to either True or False if you want dc_debug to send&lt;br /&gt;
       out its output to the python stdout interface. This is useful if you&lt;br /&gt;
       are using BF2CC and want dc_debug&#039;s output in the pythonlog.txt file.&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
import host&lt;br /&gt;
import time&lt;br /&gt;
 &lt;br /&gt;
try:&lt;br /&gt;
    debug_level_fh = open(&#039;admin/standard_admin/dc_debug.level&#039;, &#039;r&#039;)&lt;br /&gt;
    debug_level = int(debug_level_fh.read(1))&lt;br /&gt;
    debug_level_fh.close()&lt;br /&gt;
   &lt;br /&gt;
except:&lt;br /&gt;
    debug_level = 5&lt;br /&gt;
 &lt;br /&gt;
log_to_file = True&lt;br /&gt;
log_filename = &#039;dc_debug.log&#039;&lt;br /&gt;
log_to_stdout = False&lt;br /&gt;
 &lt;br /&gt;
def decho(msg, level = 1):&lt;br /&gt;
    # 1 = info w/ in-game feedback&lt;br /&gt;
    # 2 = info&lt;br /&gt;
    # 5 = debug&lt;br /&gt;
 &lt;br /&gt;
    if debug_level &amp;gt; 0 and debug_level &amp;gt;= level:&lt;br /&gt;
        string = time.strftime(&#039;%Y-%m-%d %H:%M:%S&#039;) + &#039; - &#039; + msg&lt;br /&gt;
       &lt;br /&gt;
        if log_to_stdout:&lt;br /&gt;
            print string&lt;br /&gt;
           &lt;br /&gt;
        if log_to_file:&lt;br /&gt;
            fh = open(log_filename, &#039;a&#039;)&lt;br /&gt;
            fh.write(string + &#039;\n&#039;)&lt;br /&gt;
            fh.close()&lt;br /&gt;
               &lt;br /&gt;
        if level == 1:&lt;br /&gt;
            host.rcon_invoke(&#039;game.sayall &amp;quot;%s&amp;quot;&#039; % msg)&lt;br /&gt;
 &lt;br /&gt;
def showLevel():&lt;br /&gt;
    decho(&#039;dc_debug: The current debug level is %d&#039; % debug_level, 2)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The source is downloadable from [http://dontcamp.com/code/?file=dc_debug.py&amp;amp;release=1 here]&lt;/div&gt;</summary>
		<author><name>Pireax</name></author>
	</entry>
	<entry>
		<id>https://bf2tech.uturista.pt/index.php?title=Scripts:Kicking_for_high_ping&amp;diff=103</id>
		<title>Scripts:Kicking for high ping</title>
		<link rel="alternate" type="text/html" href="https://bf2tech.uturista.pt/index.php?title=Scripts:Kicking_for_high_ping&amp;diff=103"/>
		<updated>2018-06-22T15:25:02Z</updated>

		<summary type="html">&lt;p&gt;Pireax: Created page with &amp;quot;__TOC__  = Introduction =  There are many things that may influence the quality of a BF2 server. One of them is the ping of the players. Playing against a lot of players with...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
There are many things that may influence the quality of a BF2 server. One of them is the ping of the players. Playing against a lot of players with very high ping is straight out frustrating. Therefore a lot of server-operators choose to kick players with high ping, and the best way to do it is of course to do it automatically.&lt;br /&gt;
&lt;br /&gt;
With that in mind, we at [http://www.battlefield.no/ Battlefield.no] have developed a &#039;&#039;&#039;&#039;&#039;ping kick&#039;&#039;&#039;&#039;&#039; script that solves this problem on our servers. And hopefully it can be of use to the rest of the community as well.&lt;br /&gt;
&lt;br /&gt;
Current version is 1.2, added 2005-07-03.&lt;br /&gt;
&lt;br /&gt;
= Features =&lt;br /&gt;
&lt;br /&gt;
What the the &#039;&#039;&#039;&#039;&#039;ping kick&#039;&#039;&#039;&#039;&#039; script can offer is to&lt;br /&gt;
&lt;br /&gt;
* kick people with high ping based on&lt;br /&gt;
&lt;br /&gt;
** a configurable &#039;&#039;pinglimit&#039;&#039;&lt;br /&gt;
** after a configurable number of &#039;&#039;warnings&#039;&#039; (that only appear in the debug log on the server, if enabled)&lt;br /&gt;
** with a configurable &#039;&#039;interval&#039;&#039; between ping checks&lt;br /&gt;
&lt;br /&gt;
* wait until a player has started playing before checking his/her ping, to avoid kicks on mapchange etc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Getting Started =&lt;br /&gt;
&lt;br /&gt;
To get started with the &#039;&#039;&#039;&#039;&#039;ping kick&#039;&#039;&#039;&#039;&#039; script you need to:&lt;br /&gt;
&lt;br /&gt;
* Download the script [http://www.battlefield.no/filer/pafiledb.php?action=file&amp;amp;id=191 here], and rename it to &#039;&#039;pingkick.py&#039;&#039;.&lt;br /&gt;
* Place it in the &#039;&#039;admin/standard_admin&#039;&#039; directory in your BF2 directory.&lt;br /&gt;
* Place the following code in the &#039;&#039;admin/standard_admin/__init__.py&#039;&#039; file in your BF2 directory:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
import pingkick&lt;br /&gt;
pingkick.init()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For these changes to take effect you will need to restart your BF2 server.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= The Ping Kick Script =&lt;br /&gt;
&lt;br /&gt;
This is the &#039;&#039;&#039;&#039;&#039;ping script&#039;&#039;&#039;&#039;&#039; as we use it at [http://web.archive.org/web/20081207025345/http://www.battlefield.no/ Battlefield.no]. Feel free to copy it, and since this is a wiki, feel free to modify it. But we would be very grateful of you appended a note to the updates section if you do.&lt;br /&gt;
&lt;br /&gt;
== Configuration ==&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;&#039;&#039;ping kick&#039;&#039;&#039;&#039;&#039; script comes with four settings you can change:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
autokick = 1 # Enables/disables autockicking&lt;br /&gt;
pinglimit = 150 # The ping limit, obviously ;-p&lt;br /&gt;
warnings = 3 # The number of warnings a player get before being kicked&lt;br /&gt;
interval = 30 # The interval between ping checks&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can either change these settings directly in the script, or you can make sure there exists a dictionary in the &#039;&#039;bf2&#039;&#039; object, called &#039;&#039;adminoptions&#039;&#039;, with the following keys:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pk.pingAutoKick&lt;br /&gt;
pk.pingLimit&lt;br /&gt;
pk.warnings&lt;br /&gt;
pk.interval&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If they exist, they will override the defaults set in the &#039;&#039;&#039;&#039;&#039;ping kick&#039;&#039;&#039;&#039;&#039; script. If you use our [[Scripts:Modified_admin_script|modified admin script]], the &#039;&#039;adminoptions&#039;&#039; dictionary is made available, and populated with the values in the &#039;&#039;adminsettings.con&#039;&#039; file. So remember to add the above keys with appropriate values to the file. See [[Scripts:Modified_admin_script|here]] for more details on that.&lt;br /&gt;
&lt;br /&gt;
== Output ==&lt;br /&gt;
&lt;br /&gt;
There &#039;&#039;&#039;&#039;&#039;ping kick&#039;&#039;&#039;&#039;&#039; script prints a variety of messages, but to actually view them you will need to enable debug-logging. This is done by&lt;br /&gt;
&lt;br /&gt;
* setting g_debug to 1 in &#039;&#039;&amp;lt;bf2&amp;gt;/python/bf2/__init__.py&#039;&#039;&lt;br /&gt;
* enabling a writer, like we&#039;ve done in [[Scripts:Modified_admin_script|modified admin script]]&lt;br /&gt;
&lt;br /&gt;
When a player is cought by the &#039;&#039;&#039;&#039;&#039;ping kick&#039;&#039;&#039;&#039;&#039; script with a ping that is too high, a message like the following is logged:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;[2005-07-03 04:44:28] PINGKICK: Player Panic[bf2.no] has exceeded the ping limit 2 time(s) &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And when a player has been issued the maximum number of warnings, and is being kicked, a message like the following is logged:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;[2005-07-03 04:44:43] PINGKICK: Kicking player Panic[bf2.no] for high ping ([120, 118, 118] &amp;gt; 100) &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The numbers inside the braces are ping values that has been detected and that are in violation of the ping limit. And the number to the right of the &#039;&#039;greater than&#039;&#039; sign is the ping limit.&lt;br /&gt;
&lt;br /&gt;
And five seconds before a player in violation of the ping limit is being kicked, a message like the following is printed in-game:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;BF2.NO PING KICKER: Kicking player Panic[bf2.no] for high ping. (Limit is 100, player caught with [120, 118, 118].) &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Again the numbers inside the braces are ping values that has been detected and that are in violation of the ping limit, and the first one is the ping limit. &lt;br /&gt;
&lt;br /&gt;
== The Code ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# Module: pingkick.py&lt;br /&gt;
# Authors: Kybber and Panic, Battlefield.no&lt;br /&gt;
# Version 1.2&lt;br /&gt;
# Description:&lt;br /&gt;
#   This script kicks players with high ping, based on three different&lt;br /&gt;
#   settings in the file &#039;adminsettings.con&#039;, loaded by the modified admin&lt;br /&gt;
#   script (sv.adminScript = bfno_v1.1.py). See requirements for details.&lt;br /&gt;
# Requirements:&lt;br /&gt;
#   None.&lt;br /&gt;
# Installation:&lt;br /&gt;
#   Save this script as &#039;pingkick.py&#039; in your &amp;lt;bf2&amp;gt;/admin/standard_admin directory,&lt;br /&gt;
#   and add the lines &#039;import pingkick&#039; and &#039;pingkick.init()&#039; to the file&lt;br /&gt;
#   &#039;&amp;lt;bf2&amp;gt;/admin/standard_admin/__init__.py&#039;.&lt;br /&gt;
#&lt;br /&gt;
# Changes from 1.0 to 1.1:&lt;br /&gt;
# - Added support for stand-alone operation. (Will use bf2.adminoptions if available)&lt;br /&gt;
# - The script now only checks ping while game status is &#039;Playing&#039;&lt;br /&gt;
# - Switched from &#039;bfno&#039; to prefix &#039;pk&#039; for ping kick settings in &#039;bf2.adminoptions&#039;.&lt;br /&gt;
# - Other, minor updates.&lt;br /&gt;
#&lt;br /&gt;
# Changes from 1.1. to 1.2:&lt;br /&gt;
# - Added methods to deactivate checking while players are not really playing.&lt;br /&gt;
# - Added safeguard against kicking a player that has gotten a disconnected &amp;quot;ping violater&#039;s&amp;quot; index.&lt;br /&gt;
# - Made the logging more verbose and ingame messaging less verbose.&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
#                     C O N F I G U R A T I O N&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# Settings for auto-kicking:&lt;br /&gt;
autokick = 1      # Enables/disables autockicking&lt;br /&gt;
pinglimit = 150   # The ping limit, obviously ;-p&lt;br /&gt;
warnings = 3      # The number of warnings a player get before being kicked&lt;br /&gt;
interval = 30     # The interval between ping checks&lt;br /&gt;
# NB: These settings will be overridden by their counter-parts in&lt;br /&gt;
# bf2.adminoptions[&#039;pk.&amp;lt;autoKick|pingLimit|warnings|interval&#039;]&lt;br /&gt;
# if those are present.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
#                        I M P O R T&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
import host&lt;br /&gt;
import bf2&lt;br /&gt;
from bf2 import g_debug&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
#                       V A R I A B L E S&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
# We need our own debug flag:&lt;br /&gt;
bfno_debug = False&lt;br /&gt;
&lt;br /&gt;
# Some timers:&lt;br /&gt;
pktimer   = None  # Timer firing off the ping checker. Depends on the &#039;interval&#039; variable.&lt;br /&gt;
kicktimer = None  # Timer that delays kicking after the final warning has been issued.&lt;br /&gt;
msgtimer  = None  # Timer that delays the &amp;quot;activated&amp;quot; message after entering bf2.GameStatus.Playing&lt;br /&gt;
&lt;br /&gt;
# List of people to kick for high ping. Will contain touples of p.index and p.getProfileId():&lt;br /&gt;
kicklist = []&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# For keeping track of the game status:&lt;br /&gt;
gamestatus = None&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
#                       F U N C T I O N S&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# The init function run by the standard_admin/__init__ functions:&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
def init():&lt;br /&gt;
   global interval,bfno_debug&lt;br /&gt;
   try:&lt;br /&gt;
      if bf2.bfno.debug: bfno_debug = True&lt;br /&gt;
   except:&lt;br /&gt;
      pass&lt;br /&gt;
   if bfno_debug or bfno_debug: print &#039;PINGKICK: initializing pingkick script&#039;&lt;br /&gt;
   # Try to read the settings:&lt;br /&gt;
   getSettings()&lt;br /&gt;
   # Force at least 10 seconds between ping checks:&lt;br /&gt;
   if interval &amp;lt; 10: interval = 10&lt;br /&gt;
   # Print debug message if autokick is disabled:&lt;br /&gt;
   if 1 != autokick:&lt;br /&gt;
      if bfno_debug or bfno_debug: print &#039;PINGKICK: High ping autokick not enabled&#039;&lt;br /&gt;
  &lt;br /&gt;
   # Autokick is enabled, so hook it up:&lt;br /&gt;
   else:&lt;br /&gt;
      if bfno_debug or bfno_debug: print &#039;PINGKICK: Enabling kick for high ping. Limit = %s, max warnings = %s.&#039; % (pinglimit, warnings)&lt;br /&gt;
&lt;br /&gt;
      # Register &#039;PlayerConnect&#039; callback:&lt;br /&gt;
      host.registerHandler(&#039;PlayerConnect&#039;, onPlayerConnect, 1)&lt;br /&gt;
      host.registerHandler(&#039;PlayerSpawn&#039;, onPlayerSpawn, 1)&lt;br /&gt;
      host.registerGameStatusHandler(onGameStatusChanged)&lt;br /&gt;
  &lt;br /&gt;
      # Reset TK Warnings&lt;br /&gt;
      for p in bf2.playerManager.getPlayers():&lt;br /&gt;
         onPlayerConnect(p)&lt;br /&gt;
&lt;br /&gt;
      # PingKickTimer:&lt;br /&gt;
      enableCheckTimer()&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# Get the settings from the bf2.adminsettings object:&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
def getSettings():&lt;br /&gt;
   global autokick,pinglimit,warnings,interval&lt;br /&gt;
   # Try to access the autokick setting:&lt;br /&gt;
   try:&lt;br /&gt;
      if bfno_debug: print &amp;quot;PINGKICK: Reading settings from bf2.adminoptions:&amp;quot;&lt;br /&gt;
      autokick  = int(bf2.adminoptions[&#039;pk.autoKick&#039;])&lt;br /&gt;
      pinglimit = int(bf2.adminoptions[&#039;pk.pingLimit&#039;])&lt;br /&gt;
      warnings  = int(bf2.adminoptions[&#039;pk.warnings&#039;])&lt;br /&gt;
      interval  = int(bf2.adminoptions[&#039;pk.interval&#039;])&lt;br /&gt;
   except:&lt;br /&gt;
      if bfno_debug: print &amp;quot;PINGKICK: WARNING - Could not get settings from &#039;bf2.adminoptions&#039;. Using default values:&amp;quot;&lt;br /&gt;
   if bfno_debug:&lt;br /&gt;
      print &amp;quot;  autokick  : &amp;quot; + str(autokick)&lt;br /&gt;
      print &amp;quot;  pinglimit : &amp;quot; + str(pinglimit)&lt;br /&gt;
      print &amp;quot;  maxwarns  : &amp;quot; + str(warnings)&lt;br /&gt;
      print &amp;quot;  interval  : &amp;quot; + str(interval)&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# Callback function for the &amp;quot;PlayerConnect&amp;quot; event:&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
def onPlayerConnect(p):&lt;br /&gt;
   &amp;quot;&amp;quot;&amp;quot;Resets the ping warning counter for the player&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
   resetPlayer(p)&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# Callback function for the &amp;quot;PlayerSpawn&amp;quot; event:&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
def onPlayerSpawn(p,s):&lt;br /&gt;
   &amp;quot;&amp;quot;&amp;quot;Sets the &#039;actuallyPlaying&#039; flag for the player&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
   p.actuallyPlaying = True&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# Callback function for the &amp;quot;PreGame&amp;quot; game status event:&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
def onGameStatusChanged(status):&lt;br /&gt;
   &amp;quot;&amp;quot;&amp;quot;Enables the ping check timer&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
   # Import variables, and update the game status:&lt;br /&gt;
   global gamestatus, kicklist, msgtimer&lt;br /&gt;
   gamestatus = status&lt;br /&gt;
   if gamestatus == bf2.GameStatus.Playing and autokick:&lt;br /&gt;
      if bfno_debug: print &amp;quot;PINGKICK: Setting msgtimer&amp;quot;&lt;br /&gt;
      msgtimer = bf2.Timer(onMsgTimer,10,1)&lt;br /&gt;
   # Return if not PreGame:&lt;br /&gt;
   elif gamestatus == bf2.GameStatus.PreGame:&lt;br /&gt;
      if bfno_debug: print &amp;quot;PINGKICK: Game status changed to PreGame. Get settings and and re-enabling check-timer&amp;quot;&lt;br /&gt;
      # Reset the kicklist&lt;br /&gt;
      kicklist = []&lt;br /&gt;
      # Read the settings again:&lt;br /&gt;
      getSettings()&lt;br /&gt;
      # Enable the ping check timer:&lt;br /&gt;
      enableCheckTimer()&lt;br /&gt;
   elif gamestatus == bf2.GameStatus.EndGame:&lt;br /&gt;
      # Reset players:&lt;br /&gt;
      resetPlayers()&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# Reset the bfno pingscript variables placed in the player object:&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
def resetPlayers():&lt;br /&gt;
   # Reset TK Warnings and more:&lt;br /&gt;
   for p in bf2.playerManager.getPlayers():&lt;br /&gt;
      resetPlayer(p)&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# Reset the bfno pingscript variables placed in the player object:&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
def resetPlayer(p):&lt;br /&gt;
   # Reset TK Warnings and more:&lt;br /&gt;
   p.pingWarnings = 0&lt;br /&gt;
   p.detectedPing = []&lt;br /&gt;
   p.actuallyPlaying = False&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# Callback function for timer, that delays a message at round start:&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
def onMsgTimer(data):&lt;br /&gt;
   global msgtimer&lt;br /&gt;
   if bfno_debug: print &amp;quot;PINGKICK: Entering onMsgTimer&amp;quot;&lt;br /&gt;
   msg = &amp;quot;Activated! Kicking at &amp;quot; + str(pinglimit) + &amp;quot; after &amp;quot; + str(warnings) + &amp;quot; warnings.&amp;quot;&lt;br /&gt;
   sendMsg(msg)&lt;br /&gt;
   msgtimer.destroy()&lt;br /&gt;
   msgtimer = None&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# Send text messages to the server, using rcon game.sayAll:&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
def sendMsg(msg):&lt;br /&gt;
   # Sure you can edit this, and remove &#039;bf2.no&#039;. But hey, why not give us the credit? ;-)&lt;br /&gt;
   host.rcon_invoke(&amp;quot;game.sayAll \&amp;quot;BF2.NO PING KICKER: &amp;quot; + str(msg) + &amp;quot;\&amp;quot;&amp;quot;)&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# Enable the pktimer:&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
def enableKickTimer():&lt;br /&gt;
   &amp;quot;&amp;quot;&amp;quot;Enables the timer that runs the &#039;kickPlayers&#039; functions&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
   global kicktimer&lt;br /&gt;
   if g_debug or bfno_debug: print &amp;quot;PINGKICK: Enabling the kicktimer...&amp;quot;&lt;br /&gt;
   kicktimer = bf2.Timer(kickPlayers, 5, 1)&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# Enable the pktimer:&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
def enableCheckTimer():&lt;br /&gt;
   &amp;quot;&amp;quot;&amp;quot;Enables the timer that runs the &#039;checkPing&#039; function&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
   global pktimer&lt;br /&gt;
   if pktimer:&lt;br /&gt;
      return True&lt;br /&gt;
   else:&lt;br /&gt;
      # Create the timer:&lt;br /&gt;
      if g_debug or bfno_debug: print &amp;quot;PINGKICK: Timer not enabled. Enabling...&amp;quot;&lt;br /&gt;
      pktimer = bf2.Timer(checkPing, interval, 1)&lt;br /&gt;
      pktimer.setRecurring(interval)&lt;br /&gt;
      # Print debug message telling the status of the timer:&lt;br /&gt;
      if pktimer:&lt;br /&gt;
         if g_debug and bfno_debug: print &amp;quot;PINGKICK: Time = %s&amp;quot; % (pktimer.getTime())&lt;br /&gt;
         return True&lt;br /&gt;
      else:&lt;br /&gt;
         if bfno_debug: print &amp;quot;PINGKICK: Not enabled&amp;quot;&lt;br /&gt;
         return False&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# Loop all players, checking their ping, kick high-pinger:&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
def checkPing(data):&lt;br /&gt;
   &amp;quot;&amp;quot;&amp;quot;Checks ping of all players, and kicks high-pingers&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
   global kicklist&lt;br /&gt;
&lt;br /&gt;
   # We only want to check ping during rounds:&lt;br /&gt;
   #if gamestatus != bf2.GameStatus.Playing: return&lt;br /&gt;
  &lt;br /&gt;
   # Make sure our timer is enabled:&lt;br /&gt;
   if not enableCheckTimer(): return&lt;br /&gt;
&lt;br /&gt;
   if bfno_debug: print &amp;quot;PINGKICK: Running checkPing&amp;quot;&lt;br /&gt;
&lt;br /&gt;
   # Loop all players&lt;br /&gt;
   for p in bf2.playerManager.getPlayers():&lt;br /&gt;
      # Do not check players that hasn&#039;t completed their &amp;quot;connect&amp;quot; yet:&lt;br /&gt;
      #if not p.isConnected(): continue&lt;br /&gt;
      if not p.actuallyPlaying: continue&lt;br /&gt;
      # Get the player name. We&#039;ll use it often:&lt;br /&gt;
      name = str(p.getName())&lt;br /&gt;
      # Check the ping if the limit hasn&#039;t been reached:&lt;br /&gt;
      ping = p.getPing()&lt;br /&gt;
      # If we have a valid ping, check it, and issue a warning if the ping exceeds the limit:&lt;br /&gt;
      if ping:&lt;br /&gt;
         #if bfno_debug: print &amp;quot;PINGKICK: &amp;quot; + name + &amp;quot; has &amp;quot; + str(ping) + &amp;quot; in ping and has &amp;quot; + str(p.pingWarnings) + &amp;quot; Ping-warnings&amp;quot;&lt;br /&gt;
         if ping &amp;gt; pinglimit:&lt;br /&gt;
            p.pingWarnings += 1&lt;br /&gt;
            p.detectedPing.append(ping)&lt;br /&gt;
            if g_debug or bfno_debug: print &amp;quot;PINGKICK: Player &amp;quot; + name + &amp;quot; has exceeded the ping limit &amp;quot; + str(p.pingWarnings) + &amp;quot; time(s)&amp;quot;&lt;br /&gt;
            #sendMsg(&amp;quot;WARNING: &amp;quot; + name + &amp;quot; has exeeded the ping limit &amp;quot; + str(p.pingWarnings) + &amp;quot; time(s)&amp;quot;)&lt;br /&gt;
         # Issue a warning if a player has reached the maximum number of warnings. Will be kicked next time &#039;checkPing&#039; is run:&lt;br /&gt;
         if warnings &amp;lt;= p.pingWarnings:&lt;br /&gt;
            sendMsg(&amp;quot;Kicking player &amp;quot; + name + &amp;quot; for high ping. (Limit is &amp;quot; + str(pinglimit) + &amp;quot;, player caught with &amp;quot; + str(p.detectedPing) + &amp;quot;.)&amp;quot;)&lt;br /&gt;
            # Add the player to the kicklist:&lt;br /&gt;
            kicklist.append((p.index,p.getProfileId()))&lt;br /&gt;
   # Check of we shall enable the kicktimer:&lt;br /&gt;
   if len(kicklist):&lt;br /&gt;
      enableKickTimer()&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# Function run by the kicktimer:&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
def kickPlayers(data):&lt;br /&gt;
   &amp;quot;&amp;quot;&amp;quot;Loops through &#039;kicklist&#039;, and kicks players accordingly.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
   #print &amp;quot;PINGKICK: kickPlayers...&amp;quot;&lt;br /&gt;
   global kicklist,kicktimer&lt;br /&gt;
   for i in kicklist:&lt;br /&gt;
      p = bf2.playerManager.getPlayerByIndex(i[0])&lt;br /&gt;
      # Make sure we&#039;re not kicking a player that has gotten a disconnected &amp;quot;ping violater&#039;s&amp;quot; index:&lt;br /&gt;
      if not p.getProfileId() == i[1]: continue&lt;br /&gt;
      # Check if this player has reached the limit for maximum warnongs&lt;br /&gt;
      if warnings &amp;lt;= p.pingWarnings:&lt;br /&gt;
         # Kick if limit is reached:&lt;br /&gt;
         if g_debug or bfno_debug: print &amp;quot;PINGKICK: Kicking player &amp;quot; + p.getName() + &amp;quot; for high ping (&amp;quot; + str(p.detectedPing) + &amp;quot; &amp;gt; &amp;quot;+str(pinglimit)+&amp;quot;)&amp;quot;&lt;br /&gt;
         result = host.rcon_invoke(&amp;quot;admin.kickPlayer &amp;quot; + str(p.index))&lt;br /&gt;
   kicklist = []&lt;br /&gt;
   kicktimer.destroy()&lt;br /&gt;
   kicktimer = None&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Updates ==&lt;br /&gt;
&lt;br /&gt;
Please add a note here if you update the code above.&lt;br /&gt;
&lt;br /&gt;
* 2005-07-03: Updated code and documentation to v1.2 (Panic)&lt;br /&gt;
* 2005-06-18: Updated code and documentation to v1.1 (Panic)&lt;br /&gt;
* 2005-06-18: Added documentation (Panic)&lt;br /&gt;
* 2005-06-17: Added v1.0 of the code (Panic)&lt;/div&gt;</summary>
		<author><name>Pireax</name></author>
	</entry>
	<entry>
		<id>https://bf2tech.uturista.pt/index.php?title=Scripts:IdleKick&amp;diff=102</id>
		<title>Scripts:IdleKick</title>
		<link rel="alternate" type="text/html" href="https://bf2tech.uturista.pt/index.php?title=Scripts:IdleKick&amp;diff=102"/>
		<updated>2018-06-22T15:24:32Z</updated>

		<summary type="html">&lt;p&gt;Pireax: Created page with &amp;quot;&amp;lt;pre&amp;gt;  # ------------------------------------------------------------------------  # Module: IdleKick.py  # Authors: xlr8or, www.xlr8or.com  # Version 2.02  # Description:  #...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
 # ------------------------------------------------------------------------&lt;br /&gt;
 # Module: IdleKick.py&lt;br /&gt;
 # Authors: xlr8or, www.xlr8or.com&lt;br /&gt;
 # Version 2.02&lt;br /&gt;
 # Description:&lt;br /&gt;
 #   This script kicks players who are idle, based on the configuration settings below.&lt;br /&gt;
 # Requirements:&lt;br /&gt;
 #   None.&lt;br /&gt;
 # Installation:&lt;br /&gt;
 #   Save this script as &#039;IdleKick.py&#039; in your &amp;lt;bf2&amp;gt;/admin/standard_admin directory,&lt;br /&gt;
 #   and add the lines &#039;import IdleKick&#039; and &#039;IdleKick.init()&#039; to the file&lt;br /&gt;
 #   &#039;&amp;lt;bf2&amp;gt;/admin/standard_admin/__init__.py&#039;.&lt;br /&gt;
 # Credit:&lt;br /&gt;
 #   This script is based on the pingkick script from the guys at bf2.no&lt;br /&gt;
 #   Format is mainly the same as what they did, and where I could use their&lt;br /&gt;
 #   code I have shamelessly done so.&lt;br /&gt;
 #   Credit therefor goes to Kybber and Panic, Battlefield.no&lt;br /&gt;
 # History:&lt;br /&gt;
 #   Autobalancing is a nice feature, but not when a large part of your team&lt;br /&gt;
 #   is doing something else, while staying ingame to not lose their slot.&lt;br /&gt;
 #   BF2 does not have a spectator ability, so if you&#039;re not participating,&lt;br /&gt;
 #   you&#039;re letting your team down!&lt;br /&gt;
 # Version 1.00 to 2.00:&lt;br /&gt;
 #   Cleaned some code up, added the ability to exclude clanmembers.&lt;br /&gt;
 # Version 2.00 to 2.01:&lt;br /&gt;
 #   Cleaned and corrected some global def&#039;s.&lt;br /&gt;
 # Version 2.01 to 2.02:&lt;br /&gt;
 #   Fixed the clantag protection.&lt;br /&gt;
 # ------------------------------------------------------------------------&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 # ------------------------------------------------------------------------&lt;br /&gt;
 #                     C O N F I G U R A T I O N&lt;br /&gt;
 # ------------------------------------------------------------------------&lt;br /&gt;
 # Settings for auto-kicking:&lt;br /&gt;
 autokick    = 1      # Enables/disables autokicking&lt;br /&gt;
 warnings    = 10     # The number of checks/warns a player has to fail/get before being kicked&lt;br /&gt;
 interval    = 30     # The interval between idle checks&lt;br /&gt;
 minplayers  = 5      # The minimum ammount of players online before checking idle players.&lt;br /&gt;
 announceme  = 0      # Announce the module at roundstart?&lt;br /&gt;
 warnme      = 1      # Warn the idle player 3 intervals before the maximum nr of warnings is reached?&lt;br /&gt;
 &lt;br /&gt;
 clantags = [&amp;quot;[XLR]&amp;quot;,&amp;quot;[xlr]&amp;quot;,&amp;quot;xlr8or&amp;quot;] # Clantags to protect from being kicked&lt;br /&gt;
 &lt;br /&gt;
 # ------------------------------------------------------------------------&lt;br /&gt;
 #                        I M P O R T&lt;br /&gt;
 # ------------------------------------------------------------------------&lt;br /&gt;
 &lt;br /&gt;
 import host&lt;br /&gt;
 import bf2&lt;br /&gt;
 from bf2 import g_debug&lt;br /&gt;
 &lt;br /&gt;
 # ------------------------------------------------------------------------&lt;br /&gt;
 #                       V A R I A B L E S&lt;br /&gt;
 # ------------------------------------------------------------------------&lt;br /&gt;
 &lt;br /&gt;
 # Let&#039;s set up our debug flag:&lt;br /&gt;
 xlr_debug = False&lt;br /&gt;
 &lt;br /&gt;
 # The timers:&lt;br /&gt;
 IkCheckTimer    = None  # Timer firing off the idle checker. Depends on the &#039;interval&#039; variable.&lt;br /&gt;
 KickTimer       = None  # Timer that delays kicking after the final warning has been issued.&lt;br /&gt;
 AnnounceTimer   = None  # Timer that delays the &amp;quot;activated&amp;quot; message after entering bf2.GameStatus.Playing&lt;br /&gt;
 &lt;br /&gt;
 # List of people to kick for high idle. Will contain touples of p.index and p.getProfileId():&lt;br /&gt;
 kicklist = []&lt;br /&gt;
 &lt;br /&gt;
 # For keeping track of the game status:&lt;br /&gt;
 gamestatus = None&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 # ------------------------------------------------------------------------&lt;br /&gt;
 #                       F U N C T I O N S&lt;br /&gt;
 # ------------------------------------------------------------------------&lt;br /&gt;
 &lt;br /&gt;
 # ------------------------------------------------------------------------&lt;br /&gt;
 # The init function is run by the standard_admin/__init__ functions:&lt;br /&gt;
 # ------------------------------------------------------------------------&lt;br /&gt;
 def init():&lt;br /&gt;
 &lt;br /&gt;
    if g_debug or xlr_debug: print &#039;IDLEKICK: initializing IdleKick script&#039;&lt;br /&gt;
    # Force at least 20 seconds between idle checks:&lt;br /&gt;
    if interval &amp;lt; 10: interval = 10&lt;br /&gt;
    # Print debug message if autokick is disabled:&lt;br /&gt;
    if autokick != 1:&lt;br /&gt;
       if g_debug or xlr_debug: print &#039;IDLEKICK: Idle autokick not enabled&#039;&lt;br /&gt;
   &lt;br /&gt;
    # Autokick is enabled, so hook it up:&lt;br /&gt;
    else:&lt;br /&gt;
       if g_debug or xlr_debug: print &#039;IDLEKICK: Enabling kick for being idle. Max. checkfails = %s.&#039; % (warnings)&lt;br /&gt;
 &lt;br /&gt;
       # Register &#039;PlayerConnect&#039; callback:&lt;br /&gt;
       host.registerHandler(&#039;PlayerConnect&#039;, onPlayerConnect, 1)&lt;br /&gt;
       host.registerHandler(&#039;PlayerSpawn&#039;, onPlayerSpawn, 1)&lt;br /&gt;
       host.registerGameStatusHandler(onGameStatusChanged)&lt;br /&gt;
 # ------------------------------------------------------------------------&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 # ------------------------------------------------------------------------&lt;br /&gt;
 # Callback function for the &amp;quot;PlayerConnect&amp;quot; event:&lt;br /&gt;
 # ------------------------------------------------------------------------&lt;br /&gt;
 def onPlayerConnect(p):&lt;br /&gt;
    #Resets the idle warning counter for the player&lt;br /&gt;
    resetPlayer(p)&lt;br /&gt;
 # ------------------------------------------------------------------------&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 # ------------------------------------------------------------------------&lt;br /&gt;
 # Callback function for the &amp;quot;PlayerSpawn&amp;quot; event:&lt;br /&gt;
 # ------------------------------------------------------------------------&lt;br /&gt;
 def onPlayerSpawn(p,s):&lt;br /&gt;
    # Sets the &#039;actuallyPlaying&#039; flag for the player&lt;br /&gt;
    p.actuallyPlaying = True&lt;br /&gt;
    # We can reset the warnings, since the player has actually spawned.&lt;br /&gt;
    p.idleWarnings = 0&lt;br /&gt;
 # ------------------------------------------------------------------------&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 # ------------------------------------------------------------------------&lt;br /&gt;
 # Callback function for the &amp;quot;PreGame&amp;quot; game status event:&lt;br /&gt;
 # ------------------------------------------------------------------------&lt;br /&gt;
 def onGameStatusChanged(status):&lt;br /&gt;
    # Enables the idle check timer&lt;br /&gt;
    # Import variables, and update the game status:&lt;br /&gt;
    global gamestatus, kicklist, AnnounceTimer&lt;br /&gt;
   &lt;br /&gt;
    gamestatus = status&lt;br /&gt;
    if gamestatus == bf2.GameStatus.Playing:&lt;br /&gt;
       if announceme ==1:&lt;br /&gt;
          if g_debug or xlr_debug: print &amp;quot;IDLEKICK: Round Started. Setting AnnounceTimer&amp;quot;&lt;br /&gt;
          AnnounceTimer = bf2.Timer(onAnnounceTimer,10,1)&lt;br /&gt;
       if g_debug or xlr_debug: print &amp;quot;IDLEKICK: Round Started. (Re-)enabling check-timer&amp;quot;&lt;br /&gt;
       # Enable the idle check timer:&lt;br /&gt;
       enableCheckTimer()&lt;br /&gt;
    elif gamestatus == bf2.GameStatus.PreGame:&lt;br /&gt;
       if g_debug or xlr_debug: print &amp;quot;IDLEKICK: Game status changed to PreGame. Killing check-timer&amp;quot;&lt;br /&gt;
       # Kill the check-timer&lt;br /&gt;
       disableCheckTimer()&lt;br /&gt;
    elif gamestatus == bf2.GameStatus.Paused:&lt;br /&gt;
       if g_debug or xlr_debug: print &amp;quot;IDLEKICK: Game status changed to Paused. Killing check-timer&amp;quot;&lt;br /&gt;
       # Kill the check-timer&lt;br /&gt;
       disableCheckTimer()&lt;br /&gt;
    elif gamestatus == bf2.GameStatus.EndGame:&lt;br /&gt;
       if g_debug or xlr_debug: print &amp;quot;IDLEKICK: Game status changed to EndGame. Reset Players, Kicklist and killing check-timer&amp;quot;&lt;br /&gt;
       # Kill the check-timer&lt;br /&gt;
       disableCheckTimer()&lt;br /&gt;
       # Reset the kicklist&lt;br /&gt;
       kicklist = []&lt;br /&gt;
       # Reset players:&lt;br /&gt;
       resetPlayers()&lt;br /&gt;
 # ------------------------------------------------------------------------&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 # ------------------------------------------------------------------------&lt;br /&gt;
 # Reset the idlescript variables placed in the player object:&lt;br /&gt;
 # ------------------------------------------------------------------------&lt;br /&gt;
 def resetPlayers():&lt;br /&gt;
    # Reset Warnings and stuff:&lt;br /&gt;
    if g_debug or xlr_debug: print &amp;quot;IDLEKICK: Resetting Players&amp;quot;&lt;br /&gt;
    for p in bf2.playerManager.getPlayers():&lt;br /&gt;
       resetPlayer(p)&lt;br /&gt;
 # ------------------------------------------------------------------------&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 # ------------------------------------------------------------------------&lt;br /&gt;
 # Reset the idlescript variables placed in the player object:&lt;br /&gt;
 # ------------------------------------------------------------------------&lt;br /&gt;
 def resetPlayer(p):&lt;br /&gt;
    # Reset Warnings and stuff:&lt;br /&gt;
    p.idleWarnings = 0&lt;br /&gt;
    p.actuallyPlaying = False&lt;br /&gt;
 # ------------------------------------------------------------------------&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 # ------------------------------------------------------------------------&lt;br /&gt;
 # Callback function for timer, that delays a message at round start:&lt;br /&gt;
 # ------------------------------------------------------------------------&lt;br /&gt;
 def onAnnounceTimer(data):&lt;br /&gt;
    global AnnounceTimer&lt;br /&gt;
   &lt;br /&gt;
    if g_debug or xlr_debug: print &amp;quot;IDLEKICK: Entering onAnnounceTimer... Sending the Activated announcement&amp;quot;&lt;br /&gt;
    msg = &amp;quot;Activated! Kicking after &amp;quot; + str(warnings) + &amp;quot; checks.&amp;quot;&lt;br /&gt;
    sendMsg(msg)&lt;br /&gt;
    AnnounceTimer.destroy()&lt;br /&gt;
    AnnounceTimer = None&lt;br /&gt;
 # ------------------------------------------------------------------------&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 # ------------------------------------------------------------------------&lt;br /&gt;
 # Send text messages to the server, using rcon game.sayAll:&lt;br /&gt;
 # ------------------------------------------------------------------------&lt;br /&gt;
 def sendMsg(msg):&lt;br /&gt;
    # Sure you can edit this. But hey, why not give us the credit? ;-)&lt;br /&gt;
    host.rcon_invoke(&amp;quot;game.sayAll \&amp;quot;[XLR]No-Idle: &amp;quot; + str(msg) + &amp;quot;\&amp;quot;&amp;quot;)&lt;br /&gt;
 # ------------------------------------------------------------------------&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 # ------------------------------------------------------------------------&lt;br /&gt;
 # Enable the KickTimer:&lt;br /&gt;
 # ------------------------------------------------------------------------&lt;br /&gt;
 def enableKickTimer():&lt;br /&gt;
    # Enables the timer that runs the &#039;kickPlayers&#039; functions&lt;br /&gt;
    global KickTimer&lt;br /&gt;
   &lt;br /&gt;
    if g_debug or xlr_debug: print &amp;quot;IDLEKICK: Enabling the kicktimer...&amp;quot;&lt;br /&gt;
    KickTimer = bf2.Timer(kickPlayers, 5, 1)&lt;br /&gt;
 # ------------------------------------------------------------------------&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 # ------------------------------------------------------------------------&lt;br /&gt;
 # Enable the IkCheckTimer:&lt;br /&gt;
 # ------------------------------------------------------------------------&lt;br /&gt;
 def enableCheckTimer():&lt;br /&gt;
    # Enables the timer that runs the &#039;checkidle&#039; function&lt;br /&gt;
    global IkCheckTimer&lt;br /&gt;
   &lt;br /&gt;
    if IkCheckTimer:&lt;br /&gt;
       if g_debug or xlr_debug: print &amp;quot;IDLEKICK: IkCheckTimer (already) running: Next check @ %s&amp;quot; % (IkCheckTimer.getTime())&lt;br /&gt;
       return True&lt;br /&gt;
    else:&lt;br /&gt;
       # Create the timer:&lt;br /&gt;
       if g_debug or xlr_debug: print &amp;quot;IDLEKICK: Timer not enabled. Enabling...&amp;quot;&lt;br /&gt;
       IkCheckTimer = bf2.Timer(checkidle, interval, 1)&lt;br /&gt;
       IkCheckTimer.setRecurring(interval)&lt;br /&gt;
       # Print debug message telling the status of the timer:&lt;br /&gt;
       if IkCheckTimer:&lt;br /&gt;
          if g_debug or xlr_debug: print &amp;quot;IDLEKICK: First check @ %s&amp;quot; % (IkCheckTimer.getTime())&lt;br /&gt;
          return True&lt;br /&gt;
       else:&lt;br /&gt;
          if g_debug or xlr_debug: print &amp;quot;IDLEKICK: ERROR: IkCheckimer Not enabled in def enableCheckTimer()&amp;quot;&lt;br /&gt;
          return False&lt;br /&gt;
 # ------------------------------------------------------------------------&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 # ------------------------------------------------------------------------&lt;br /&gt;
 # Disable the IkCheckTimer:&lt;br /&gt;
 # ------------------------------------------------------------------------&lt;br /&gt;
 def disableCheckTimer():&lt;br /&gt;
    global IkCheckTimer&lt;br /&gt;
   &lt;br /&gt;
    IkCheckTimer.destroy()&lt;br /&gt;
    IkCheckTimer = None&lt;br /&gt;
 &lt;br /&gt;
 # ------------------------------------------------------------------------&lt;br /&gt;
 &lt;br /&gt;
 # ------------------------------------------------------------------------&lt;br /&gt;
 # Loop all players, checking their idle, kick high-idleer:&lt;br /&gt;
 # ------------------------------------------------------------------------&lt;br /&gt;
 def checkidle(data):&lt;br /&gt;
    # Checks idle of all players, and kicks idlers&lt;br /&gt;
    global kicklist, gamestatus&lt;br /&gt;
 &lt;br /&gt;
    # We only want to check idle during rounds:&lt;br /&gt;
    if gamestatus != bf2.GameStatus.Playing: return&lt;br /&gt;
   &lt;br /&gt;
    # Make sure our timer is enabled:&lt;br /&gt;
    if not enableCheckTimer(): return&lt;br /&gt;
   &lt;br /&gt;
    if bf2.playerManager.getNumberOfPlayers() &amp;lt; minplayers:&lt;br /&gt;
       if g_debug or xlr_debug: print &amp;quot;IDLEKICK: Not enough players to check for idlers...&amp;quot;&lt;br /&gt;
       return&lt;br /&gt;
 &lt;br /&gt;
    if g_debug or xlr_debug: print &amp;quot;IDLEKICK: Running checkidle&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
    # Loop all players&lt;br /&gt;
    for p in bf2.playerManager.getPlayers():&lt;br /&gt;
       # Do not check players that haven&#039;t completed their &amp;quot;connect&amp;quot; yet:&lt;br /&gt;
       if not p.isConnected():&lt;br /&gt;
         if g_debug or xlr_debug: print &amp;quot;IDLEKICK: Player not yet connected, continuing...&amp;quot;&lt;br /&gt;
         continue&lt;br /&gt;
       if p.isAlive():&lt;br /&gt;
         if g_debug or xlr_debug: print &amp;quot;IDLEKICK: Player is already playing, continuing...&amp;quot;&lt;br /&gt;
         continue&lt;br /&gt;
       if p.isManDown():&lt;br /&gt;
         if g_debug or xlr_debug: print &amp;quot;IDLEKICK: Player in ManDown state, continuing...&amp;quot;&lt;br /&gt;
         continue&lt;br /&gt;
       # Get the player name. We&#039;ll use it often:&lt;br /&gt;
       name = str(p.getName())&lt;br /&gt;
 &lt;br /&gt;
       # Prevent Clanmembers from being kicked&lt;br /&gt;
       skip = 0&lt;br /&gt;
       for clantag in clantags:&lt;br /&gt;
         if name.find(clantag)&amp;gt;-1:&lt;br /&gt;
           skip = 1&lt;br /&gt;
           break&lt;br /&gt;
       if skip == 1: continue&lt;br /&gt;
 &lt;br /&gt;
       # If we have a valid idle, check it, and issue a warning if the idle exceeds the limit:&lt;br /&gt;
       p.idleWarnings += 1&lt;br /&gt;
       if g_debug or xlr_debug: print &amp;quot;IDLEKICK: Player &amp;quot; + name + &amp;quot; has been detected as idle &amp;quot; + str(p.idleWarnings) + &amp;quot; time(s)&amp;quot;&lt;br /&gt;
       if warnme == 1 and p.idleWarnings == (warnings - 3):&lt;br /&gt;
         #tmp = p.idleWarnings * interval / 60&lt;br /&gt;
         sendMsg(&amp;quot;WARNING: &amp;quot; + name + &amp;quot; has not returned to duty for quite some time now. Move in fast, you&#039;re about to be court marshalled!&amp;quot;)&lt;br /&gt;
       # Issue a warning if a player has reached the maximum number of warnings. Will be kicked next time &#039;checkidle&#039; is run:&lt;br /&gt;
       if warnings &amp;lt;= p.idleWarnings:&lt;br /&gt;
         #tmp = p.idleWarnings * intervals / 60&lt;br /&gt;
         sendMsg(&amp;quot;Desertion Violation: &amp;quot; + name + &amp;quot; is being removed for not returning to duty in time! (aka idling)&amp;quot;)&lt;br /&gt;
         # Add the player to the kicklist:&lt;br /&gt;
         kicklist.append((p.index,p.getProfileId()))&lt;br /&gt;
 &lt;br /&gt;
    # Check of we shall enable the kicktimer:&lt;br /&gt;
    if len(kicklist):&lt;br /&gt;
       enableKickTimer()&lt;br /&gt;
 # ------------------------------------------------------------------------&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 # ------------------------------------------------------------------------&lt;br /&gt;
 # Function run by the kicktimer:&lt;br /&gt;
 # ------------------------------------------------------------------------&lt;br /&gt;
 def kickPlayers(data):&lt;br /&gt;
    # Loops through &#039;kicklist&#039;, and kicks players accordingly.&lt;br /&gt;
    #print &amp;quot;IDLEKICK: kickPlayers...&amp;quot;&lt;br /&gt;
    global kicklist, KickTimer&lt;br /&gt;
   &lt;br /&gt;
    for i in kicklist:&lt;br /&gt;
       p = bf2.playerManager.getPlayerByIndex(i[0])&lt;br /&gt;
       # Make sure we&#039;re not kicking a player that has gotten an already disconnected &amp;quot;violater&#039;s&amp;quot; index:&lt;br /&gt;
       if not p.getProfileId() == i[1]: continue&lt;br /&gt;
       # Check if this player indeed has reached the limit for maximum warnings&lt;br /&gt;
       if warnings &amp;lt;= p.idleWarnings:&lt;br /&gt;
          # Kick if limit is reached:&lt;br /&gt;
          if g_debug or xlr_debug: print &amp;quot;IDLEKICK: Kicking player &amp;quot; + p.getName() + &amp;quot; for being idle.&amp;quot;&lt;br /&gt;
          result = host.rcon_invoke(&amp;quot;admin.kickPlayer &amp;quot; + str(p.index))&lt;br /&gt;
    kicklist = []&lt;br /&gt;
    KickTimer.destroy()&lt;br /&gt;
    KickTimer = None&lt;br /&gt;
 # ------------------------------------------------------------------------&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Pireax</name></author>
	</entry>
	<entry>
		<id>https://bf2tech.uturista.pt/index.php?title=Scripts:CountryFilter&amp;diff=101</id>
		<title>Scripts:CountryFilter</title>
		<link rel="alternate" type="text/html" href="https://bf2tech.uturista.pt/index.php?title=Scripts:CountryFilter&amp;diff=101"/>
		<updated>2018-06-22T15:24:07Z</updated>

		<summary type="html">&lt;p&gt;Pireax: Created page with &amp;quot;== Description ==  The feature of CountryFilter is as follows.  * This script can display country name by finding the country from IP-address of the player. * This script prov...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Description ==&lt;br /&gt;
&lt;br /&gt;
The feature of CountryFilter is as follows.&lt;br /&gt;
&lt;br /&gt;
* This script can display country name by finding the country from IP-address of the player.&lt;br /&gt;
* This script provides access control (allow/deny) based on player country name.&lt;br /&gt;
* This script uses GeoIP Free Country, and its accuracy of conversion is approximately 97%.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== The Code ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt; &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt; &amp;lt;/code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
# CountryFilter.py&lt;br /&gt;
#&lt;br /&gt;
# Copyright (C) 2005 Guwashi &amp;lt;guwashi[AT]fooos[DOT]com&amp;gt;&lt;br /&gt;
#&lt;br /&gt;
# This library is free software; you can redistribute it and/or&lt;br /&gt;
# modify it under the terms of the GNU General Public&lt;br /&gt;
# License as published by the Free Software Foundation; either&lt;br /&gt;
# version 2.1 of the License, or (at your option) any later version.&lt;br /&gt;
#&lt;br /&gt;
# This library is distributed in the hope that it will be useful,&lt;br /&gt;
# but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU&lt;br /&gt;
# General Public License for more details.&lt;br /&gt;
#&lt;br /&gt;
# You should have received a copy of the GNU General Public&lt;br /&gt;
# License along with this library; if not, write to the Free Software&lt;br /&gt;
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA&lt;br /&gt;
&lt;br /&gt;
# Description:&lt;br /&gt;
#&lt;br /&gt;
#   The feature of CountryFilter is as follows.&lt;br /&gt;
#&lt;br /&gt;
#     - This script can display country name by finding the country&lt;br /&gt;
#       from IP-address of the player.&lt;br /&gt;
#&lt;br /&gt;
#     - This script provides access control (allow/deny) based on&lt;br /&gt;
#       player country name.&lt;br /&gt;
#&lt;br /&gt;
#     - This script uses GeoIP Free Country, and its accuracy of&lt;br /&gt;
#       conversion is approximately 97%.&lt;br /&gt;
#&lt;br /&gt;
#   If you want to see latest information of this script, please&lt;br /&gt;
#   acccess this URL.&lt;br /&gt;
#   http://d3.jpn.org/&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
# Download:&lt;br /&gt;
#&lt;br /&gt;
#   http://d3.jpn.org/bf2/CountryFilter-bf2-1.0.0.zip&lt;br /&gt;
#   http://www.maxmind.com/download/geoip/database/GeoIP.dat.gz&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
# Install:&lt;br /&gt;
#&lt;br /&gt;
#   - Copy CountryFilter.py and PurePythonGeoIP.py to&lt;br /&gt;
#     &#039;&amp;lt;bf2&amp;gt;/Admin/standard_admin&#039; directory.&lt;br /&gt;
#&lt;br /&gt;
#   - Add the lines &#039;import CountryFilter&#039; and &#039;CountryFilter.init()&#039;&lt;br /&gt;
#     to the file &#039;&amp;lt;bf2&amp;gt;/admin/standard_admin/__init__.py&#039;.&lt;br /&gt;
#&lt;br /&gt;
#     ex.)&lt;br /&gt;
#       import autobalance&lt;br /&gt;
#       import tk_punish&lt;br /&gt;
#       import CountryFilter&lt;br /&gt;
#&lt;br /&gt;
#       autobalance.init()&lt;br /&gt;
#       tk_punish.init()   &lt;br /&gt;
#       CountryFilter.init()&lt;br /&gt;
#&lt;br /&gt;
#   - Download GeoIP.dat from&lt;br /&gt;
#     http://www.maxmind.com/download/geoip/database/GeoIP.dat.gz&lt;br /&gt;
#     and extract it.&lt;br /&gt;
#&lt;br /&gt;
#   - Copy GeoIP.dat to &#039;&amp;lt;bf2&amp;gt;&#039; directory.&lt;br /&gt;
#&lt;br /&gt;
#   - Finally, it must be the following.&lt;br /&gt;
#&lt;br /&gt;
#     ex.)&lt;br /&gt;
#       &amp;lt;bf2&amp;gt;/Admin/standard_admin/CountryFilter.py&lt;br /&gt;
#       &amp;lt;bf2&amp;gt;/Admin/standard_admin/PurePythonGeoIP.py&lt;br /&gt;
#       &amp;lt;bf2&amp;gt;/GeoIP.dat&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
# Config:&lt;br /&gt;
#&lt;br /&gt;
#   see also&lt;br /&gt;
#   http://d3.jpn.org/hl2/CountryFilter-en.html (English)&lt;br /&gt;
#   http://d3.jpn.org/hl2/CountryFilter-jp.html (Japanese)&lt;br /&gt;
#&lt;br /&gt;
#   - You can customize the print format of country.&lt;br /&gt;
#&lt;br /&gt;
#     - Country code by two characters.  ex.) JP&lt;br /&gt;
#&lt;br /&gt;
cf_country_print_mode = &#039;code&#039;&lt;br /&gt;
#&lt;br /&gt;
#     - Country code by three characters.  ex.) JPN&lt;br /&gt;
#&lt;br /&gt;
#cf_country_print_mode = &#039;code3&#039;&lt;br /&gt;
#&lt;br /&gt;
#     - Long country name.  ex.) Japan&lt;br /&gt;
#&lt;br /&gt;
#cf_country_print_mode = &#039;name&#039;&lt;br /&gt;
#&lt;br /&gt;
#   - You can customize the message format when script allow/deny the&lt;br /&gt;
#     connection according to the country of the player.&lt;br /&gt;
#&lt;br /&gt;
#     - Message format when player was allowed to connect.&lt;br /&gt;
#       %(name)s is replaced with player name.&lt;br /&gt;
#       %(country)s is replaced with country name.&lt;br /&gt;
#       The message will not displayed when setting as&lt;br /&gt;
#       cf_allow_message = &#039;&#039;.&lt;br /&gt;
#&lt;br /&gt;
cf_allow_message = &#039;%(name)s (Country: %(country)s) was allowed to connect.&#039;&lt;br /&gt;
#&lt;br /&gt;
#     - Message format when player was denied to connect.&lt;br /&gt;
#       %(name)s is replaced with player name.&lt;br /&gt;
#       %(country)s is replaced with country name.&lt;br /&gt;
#       The message will not displayed when setting as&lt;br /&gt;
#       cf_deny_message = &#039;&#039;.&lt;br /&gt;
#&lt;br /&gt;
cf_deny_message =  &#039;%(name)s (Country: %(country)s) was rejected by CountryFilter.&#039;&lt;br /&gt;
#&lt;br /&gt;
#     - Specify the country(s) which is excluded from printing&lt;br /&gt;
#       messages.&lt;br /&gt;
#       Available value is same as cf_allow_from and cf_deny_from.&lt;br /&gt;
#&lt;br /&gt;
cf_message_exclude_from = &#039;&#039;&lt;br /&gt;
#&lt;br /&gt;
#   - Allowing/denying the connection according to the country of the&lt;br /&gt;
#     player.&lt;br /&gt;
#&lt;br /&gt;
#     You can limit the connection by using cf_allow_from,&lt;br /&gt;
#     cf_deny_from, and cf_order. Please specify this by the country&lt;br /&gt;
#     code of two characters. Basically, it is the same as the&lt;br /&gt;
#     mod_access module of Apache. See this URL.&lt;br /&gt;
#&lt;br /&gt;
#     http://httpd.apache.org/docs/mod/mod_access.html&lt;br /&gt;
#&lt;br /&gt;
#     - cf_allow_from&lt;br /&gt;
#&lt;br /&gt;
#       cf_allow_from specify the country(s) which is allowed to&lt;br /&gt;
#       connect. Available value of cf_allow_from is &#039;all&#039;, &#039;&#039;, &#039;--&#039;&lt;br /&gt;
#       and country code by 2 characters. If you want to specify&lt;br /&gt;
#       multiple value, use space as delimiter. Set &#039;all&#039;, if you want&lt;br /&gt;
#       to allow all countries. When &#039;&#039; (null string) is specified,&lt;br /&gt;
#       nothing is done. &#039;--&#039; is unknown country. Note: when you&lt;br /&gt;
#       connect to server from LAN, its IP-address is 192.168.xxx.xxx,&lt;br /&gt;
#       so this script cannot find valid country name. Therefore if&lt;br /&gt;
#       you want to allow to connect from LAN, you must specify &#039;--&#039;.&lt;br /&gt;
#&lt;br /&gt;
#       ex.1)&lt;br /&gt;
#         # Allowing all countries.&lt;br /&gt;
#         cf_allow_from = &#039;all&#039;&lt;br /&gt;
#&lt;br /&gt;
#       ex.2)&lt;br /&gt;
#         # Allowing only JP, US and LAN.&lt;br /&gt;
#         cf_allow_from = &#039;JP US --&#039;&lt;br /&gt;
#&lt;br /&gt;
#       ex.3)&lt;br /&gt;
#         # Doing nothing.&lt;br /&gt;
#         cf_allow_from = &#039;&#039;&lt;br /&gt;
#&lt;br /&gt;
#     - cf_deny_from&lt;br /&gt;
#&lt;br /&gt;
#       cf_deny_from specify the country(s) which is deny to&lt;br /&gt;
#       connect. Available value of cf_deny_from is quite the same as&lt;br /&gt;
#       cf_allow_from.&lt;br /&gt;
#&lt;br /&gt;
#     - cf_order&lt;br /&gt;
#&lt;br /&gt;
#       cf_order controls the default access state and the order in&lt;br /&gt;
#       which cf_allow_from and cf_deny_from are evaluated. The value&lt;br /&gt;
#       of cf_order must be &amp;quot;deny,allow&amp;quot; or &amp;quot;allow,deny&amp;quot;. The default&lt;br /&gt;
#       value is &amp;quot;deny,allow&amp;quot;.&lt;br /&gt;
#&lt;br /&gt;
#       ex.1)&lt;br /&gt;
#         # It is evaluated in order of deny and allow.&lt;br /&gt;
#         # Access is allowed by default.&lt;br /&gt;
#         cf_order = &#039;deny,allow&#039;&lt;br /&gt;
#&lt;br /&gt;
#       ex.2)&lt;br /&gt;
#         # It is evaluated in order of allow and deny.&lt;br /&gt;
#         # Access is denied by default.&lt;br /&gt;
#         cf_order = &#039;allow,deny&#039;&lt;br /&gt;
#&lt;br /&gt;
#     - Examples&lt;br /&gt;
#&lt;br /&gt;
#       Some typical usages are shown as follows.&lt;br /&gt;
#&lt;br /&gt;
#       - Allowing all countries. (default)&lt;br /&gt;
#&lt;br /&gt;
cf_order = &#039;deny,allow&#039;&lt;br /&gt;
cf_deny_from = &#039;&#039;&lt;br /&gt;
cf_allow_from = &#039;all&#039;&lt;br /&gt;
#&lt;br /&gt;
#       - Allowing only JP, US and LAN. Others are denied.&lt;br /&gt;
#&lt;br /&gt;
#cf_order = &#039;deny,allow&#039;&lt;br /&gt;
#cf_deny_from = &#039;all&#039;&lt;br /&gt;
#cf_allow_from = &#039;JP US --&#039;&lt;br /&gt;
#&lt;br /&gt;
#       - Denying only JP. Others are allowed.&lt;br /&gt;
#&lt;br /&gt;
#cf_order = &#039;allow,deny&#039;&lt;br /&gt;
#cf_allow_from = &#039;all&#039;&lt;br /&gt;
#cf_deny_from = &#039;JP&#039;&lt;br /&gt;
#&lt;br /&gt;
#       If you want to find country code, refer this page.&lt;br /&gt;
#       http://www.maxmind.com/app/iso3166&lt;br /&gt;
#&lt;br /&gt;
#   - Specify the path of GeoIP.dat file. Default path is&lt;br /&gt;
#     &amp;lt;bf2&amp;gt;/GeoIP.dat.&lt;br /&gt;
#&lt;br /&gt;
cf_geoipdat_path = &#039;GeoIP.dat&#039;&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
# etc.:&lt;br /&gt;
#&lt;br /&gt;
#   - The CountryFilter is licensed under the GPL. For details see the&lt;br /&gt;
#     COPYING file.&lt;br /&gt;
#&lt;br /&gt;
#   - This product includes GeoIP data created by MaxMind, available&lt;br /&gt;
#     from http://maxmind.com/&lt;br /&gt;
#&lt;br /&gt;
#&lt;br /&gt;
# Author:&lt;br /&gt;
#&lt;br /&gt;
#   Guwashi&lt;br /&gt;
#     - E-Mail&lt;br /&gt;
#       guwashi[AT]fooos[DOT]com&lt;br /&gt;
#     - Web&lt;br /&gt;
#       http://d3.jpn.org/&lt;br /&gt;
#     - Forums&lt;br /&gt;
#       not yet.&lt;br /&gt;
#&lt;br /&gt;
# ChangeLog:&lt;br /&gt;
#&lt;br /&gt;
#   - 1.0.0 2005/07/07&lt;br /&gt;
#     first public release.&lt;br /&gt;
#   - 1.0.0rc1 2005/07/06&lt;br /&gt;
#     added cf_country_print_mode, cf_message_exclude_from and&lt;br /&gt;
#     cf_geoipdat_path.&lt;br /&gt;
#   - 1.0.0b 2005/07/04&lt;br /&gt;
#     first beta.&lt;br /&gt;
&lt;br /&gt;
import sys&lt;br /&gt;
import re&lt;br /&gt;
import host&lt;br /&gt;
import bf2&lt;br /&gt;
import PurePythonGeoIP&lt;br /&gt;
from PurePythonGeoIP import GeoIP&lt;br /&gt;
&lt;br /&gt;
COUNTRYFILTER_VERSION = &#039;1.0.0&#039;&lt;br /&gt;
&lt;br /&gt;
gi = None&lt;br /&gt;
&lt;br /&gt;
def init():&lt;br /&gt;
   &#039;&#039;&#039;Create a new GeoIP object and register callback functions.&#039;&#039;&#039;&lt;br /&gt;
   global gi, cf_geoipdat_path&lt;br /&gt;
   printLog(&#039;init&#039;, &#039;start...&#039;)&lt;br /&gt;
   gi = GeoIP.open(cf_geoipdat_path, GeoIP.GEOIP_STANDARD)&lt;br /&gt;
   printLog(&#039;init&#039;, &#039;testing: 133.1.1.1 ==&amp;gt; &#039; + gi.country_code_by_addr(&#039;133.1.1.1&#039;))&lt;br /&gt;
   host.registerHandler(&#039;PlayerConnect&#039;, onPlayerConnect, 1)&lt;br /&gt;
   printLog(&#039;init&#039;, &#039;done&#039;)&lt;br /&gt;
&lt;br /&gt;
def onPlayerConnect(player):&lt;br /&gt;
   &#039;&#039;&#039;Examine players country and allow/deny to connect.&#039;&#039;&#039;&lt;br /&gt;
   global cf_allow_message, cf_deny_message&lt;br /&gt;
   printLog(&#039;onPlayerConnect&#039;, &#039;start...&#039;)&lt;br /&gt;
   printLog(&#039;onPlayerConnect&#039;, &#039;player.index == &#039; + str(player.index))&lt;br /&gt;
   printLog(&#039;onPlayerConnect&#039;, &#039;player.getName() == &#039; + str(player.getName()))&lt;br /&gt;
   printLog(&#039;onPlayerConnect&#039;, &#039;player.getAddress() == &#039; + str(player.getAddress()))&lt;br /&gt;
   countryId = gi.id_by_addr(str(player.getAddress()))&lt;br /&gt;
   countryCode = GeoIP.id_to_country_code(countryId)&lt;br /&gt;
   country = idToCountry(countryId)&lt;br /&gt;
   printLog(&#039;onPlayerConnect&#039;, &#039;country == &#039; + country)&lt;br /&gt;
   if isAllowConnect(countryCode):&lt;br /&gt;
      if 0 &amp;lt; len(cf_allow_message) and (not isMessageExcludeFrom(countryCode)):&lt;br /&gt;
         message = cf_allow_message % {&#039;name&#039;:player.getName(), &#039;country&#039;:country}&lt;br /&gt;
         printConsole(message)&lt;br /&gt;
         sayAll(message)&lt;br /&gt;
      pass # do nothing&lt;br /&gt;
   else:&lt;br /&gt;
      if 0 &amp;lt; len(cf_deny_message) and (not isMessageExcludeFrom(countryCode)):&lt;br /&gt;
         message = cf_deny_message % {&#039;name&#039;:player.getName(), &#039;country&#039;:country}&lt;br /&gt;
         printConsole(message)&lt;br /&gt;
         sayAll(message)&lt;br /&gt;
      host.rcon_invoke(&#039;admin.kickPlayer &#039; + str(player.index)) # kick!&lt;br /&gt;
   printLog(&#039;onPlayerConnect&#039;, &#039;done&#039;)&lt;br /&gt;
&lt;br /&gt;
def printLog(method_name, message):&lt;br /&gt;
   &#039;&#039;&#039;Print log to stdout.&#039;&#039;&#039;&lt;br /&gt;
   if bf2.g_debug:&lt;br /&gt;
      print &#039;[CF]: &#039; + str(method_name) + &#039;: &#039; + str(message)&lt;br /&gt;
      sys.stdout.flush()&lt;br /&gt;
&lt;br /&gt;
def printConsole(message):&lt;br /&gt;
   &#039;&#039;&#039;Print log to server console.&#039;&#039;&#039;&lt;br /&gt;
   host.rcon_invoke(&#039;echo &amp;quot;&#039; + str(message) + &#039;&amp;quot;&#039;)&lt;br /&gt;
&lt;br /&gt;
def sayAll(message):&lt;br /&gt;
   &#039;&#039;&#039;Say message to to all players.&#039;&#039;&#039;&lt;br /&gt;
   host.rcon_invoke(&#039;game.sayAll &amp;quot;&#039; + str(message) + &#039;&amp;quot;&#039;)&lt;br /&gt;
&lt;br /&gt;
def isAllowConnect(countryCode):&lt;br /&gt;
   &#039;&#039;&#039;Is player allowed to connect?&#039;&#039;&#039;&lt;br /&gt;
   # http://httpd.apache.org/docs/mod/mod_access.html&lt;br /&gt;
   # TODO: use regular expressions&lt;br /&gt;
   global cf_order, cf_allow_from, cf_deny_from&lt;br /&gt;
   result = True&lt;br /&gt;
   if &#039;allow,deny&#039; == cf_order:&lt;br /&gt;
      result = False # deny&lt;br /&gt;
      if -1 != cf_allow_from.find(&#039;all&#039;):&lt;br /&gt;
         result = True&lt;br /&gt;
      if -1 != cf_allow_from.find(countryCode):&lt;br /&gt;
         result = True&lt;br /&gt;
      if -1 != cf_deny_from.find(&#039;all&#039;):&lt;br /&gt;
         result = False&lt;br /&gt;
      if -1 != cf_deny_from.find(countryCode):&lt;br /&gt;
         result = False&lt;br /&gt;
   else: # &#039;deny,allow&#039; (default)&lt;br /&gt;
      result = True; # allow&lt;br /&gt;
      if -1 != cf_deny_from.find(&#039;all&#039;):&lt;br /&gt;
         result = False&lt;br /&gt;
      if -1 != cf_deny_from.find(countryCode):&lt;br /&gt;
         result = False&lt;br /&gt;
      if -1 != cf_allow_from.find(&#039;all&#039;):&lt;br /&gt;
         result = True&lt;br /&gt;
      if -1 != cf_allow_from.find(countryCode):&lt;br /&gt;
         result = True&lt;br /&gt;
   return result;&lt;br /&gt;
&lt;br /&gt;
def isMessageExcludeFrom(countryCode):&lt;br /&gt;
   &#039;&#039;&#039;Is message allowed to print?&#039;&#039;&#039;&lt;br /&gt;
   global cf_message_exclude_from&lt;br /&gt;
   result = False&lt;br /&gt;
   if -1 != cf_message_exclude_from.find(&#039;all&#039;):&lt;br /&gt;
      result = True&lt;br /&gt;
   if -1 != cf_message_exclude_from.find(countryCode):&lt;br /&gt;
      result = True&lt;br /&gt;
   return result&lt;br /&gt;
&lt;br /&gt;
def idToCountry(countryId):&lt;br /&gt;
   &#039;&#039;&#039;Convert country id to country representation.&#039;&#039;&#039;&lt;br /&gt;
   global cf_country_print_mode&lt;br /&gt;
   if &#039;code3&#039; == cf_country_print_mode:&lt;br /&gt;
      return GeoIP.id_to_country_code3(countryId)&lt;br /&gt;
   elif &#039;name&#039; == cf_country_print_mode:&lt;br /&gt;
      return GeoIP.id_to_country_name(countryId)&lt;br /&gt;
   else: # &#039;code&#039; (default)&lt;br /&gt;
      return GeoIP.id_to_country_code(countryId)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;/code&amp;gt; &amp;lt;code&amp;gt; &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt; &amp;lt;/code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
#! /usr/bin/python&lt;br /&gt;
&lt;br /&gt;
# PurePythonGeoIP.py&lt;br /&gt;
#&lt;br /&gt;
# Copyright (C) 2005 Guwashi &amp;lt;guwashi[AT]fooos[DOT]com&amp;gt;&lt;br /&gt;
#&lt;br /&gt;
# This library is free software; you can redistribute it and/or&lt;br /&gt;
# modify it under the terms of the GNU General Public&lt;br /&gt;
# License as published by the Free Software Foundation; either&lt;br /&gt;
# version 2.1 of the License, or (at your option) any later version.&lt;br /&gt;
#&lt;br /&gt;
# This library is distributed in the hope that it will be useful,&lt;br /&gt;
# but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU&lt;br /&gt;
# General Public License for more details.&lt;br /&gt;
#&lt;br /&gt;
# You should have received a copy of the GNU General Public&lt;br /&gt;
# License along with this library; if not, write to the Free Software&lt;br /&gt;
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA&lt;br /&gt;
&lt;br /&gt;
# This code is based on&lt;br /&gt;
# http://www.maxmind.com/app/python&lt;br /&gt;
# http://www.maxmind.com/download/geoip/api/pureperl&lt;br /&gt;
&lt;br /&gt;
import re&lt;br /&gt;
import struct&lt;br /&gt;
&lt;br /&gt;
PUREPYTHONGEOIP_VERSION = &#039;1.0.0&#039;&lt;br /&gt;
&lt;br /&gt;
def nreverse(sequence):&lt;br /&gt;
    &#039;&#039;&#039;nreverse in Common Lisp. :)&#039;&#039;&#039;&lt;br /&gt;
    sequence.reverse()&lt;br /&gt;
    return sequence&lt;br /&gt;
&lt;br /&gt;
class GeoIP:&lt;br /&gt;
    __STANDARD_RECORD_LENGTH = 3&lt;br /&gt;
    __GEOIP_COUNTRY_EDITION = 106&lt;br /&gt;
    __GEOIP_COUNTRY_BEGIN = 16776960&lt;br /&gt;
&lt;br /&gt;
    __COUNTRIES = (&#039;--&#039;,&#039;AP&#039;,&#039;EU&#039;,&#039;AD&#039;,&#039;AE&#039;,&#039;AF&#039;,&#039;AG&#039;,&#039;AI&#039;,&#039;AL&#039;,&#039;AM&#039;,&#039;AN&#039;,&#039;AO&#039;,&#039;AQ&#039;,&#039;AR&#039;,&#039;AS&#039;,&#039;AT&#039;,&#039;AU&#039;,&#039;AW&#039;,&#039;AZ&#039;,&#039;BA&#039;,&#039;BB&#039;,&#039;BD&#039;,&#039;BE&#039;,&#039;BF&#039;,&#039;BG&#039;,&#039;BH&#039;,&#039;BI&#039;,&#039;BJ&#039;,&#039;BM&#039;,&#039;BN&#039;,&#039;BO&#039;,&#039;BR&#039;,&#039;BS&#039;,&#039;BT&#039;,&#039;BV&#039;,&#039;BW&#039;,&#039;BY&#039;,&#039;BZ&#039;,&#039;CA&#039;,&#039;CC&#039;,&#039;CD&#039;,&#039;CF&#039;,&#039;CG&#039;,&#039;CH&#039;,&#039;CI&#039;,&#039;CK&#039;,&#039;CL&#039;,&#039;CM&#039;,&#039;CN&#039;,&#039;CO&#039;,&#039;CR&#039;,&#039;CU&#039;,&#039;CV&#039;,&#039;CX&#039;,&#039;CY&#039;,&#039;CZ&#039;,&#039;DE&#039;,&#039;DJ&#039;,&#039;DK&#039;,&#039;DM&#039;,&#039;DO&#039;,&#039;DZ&#039;,&#039;EC&#039;,&#039;EE&#039;,&#039;EG&#039;,&#039;EH&#039;,&#039;ER&#039;,&#039;ES&#039;,&#039;ET&#039;,&#039;FI&#039;,&#039;FJ&#039;,&#039;FK&#039;,&#039;FM&#039;,&#039;FO&#039;,&#039;FR&#039;,&#039;FX&#039;,&#039;GA&#039;,&#039;GB&#039;,&#039;GD&#039;,&#039;GE&#039;,&#039;GF&#039;,&#039;GH&#039;,&#039;GI&#039;,&#039;GL&#039;,&#039;GM&#039;,&#039;GN&#039;,&#039;GP&#039;,&#039;GQ&#039;,&#039;GR&#039;,&#039;GS&#039;,&#039;GT&#039;,&#039;GU&#039;,&#039;GW&#039;,&#039;GY&#039;,&#039;HK&#039;,&#039;HM&#039;,&#039;HN&#039;,&#039;HR&#039;,&#039;HT&#039;,&#039;HU&#039;,&#039;ID&#039;,&#039;IE&#039;,&#039;IL&#039;,&#039;IN&#039;,&#039;IO&#039;,&#039;IQ&#039;,&#039;IR&#039;,&#039;IS&#039;,&#039;IT&#039;,&#039;JM&#039;,&#039;JO&#039;,&#039;JP&#039;,&#039;KE&#039;,&#039;KG&#039;,&#039;KH&#039;,&#039;KI&#039;,&#039;KM&#039;,&#039;KN&#039;,&#039;KP&#039;,&#039;KR&#039;,&#039;KW&#039;,&#039;KY&#039;,&#039;KZ&#039;,&#039;LA&#039;,&#039;LB&#039;,&#039;LC&#039;,&#039;LI&#039;,&#039;LK&#039;,&#039;LR&#039;,&#039;LS&#039;,&#039;LT&#039;,&#039;LU&#039;,&#039;LV&#039;,&#039;LY&#039;,&#039;MA&#039;,&#039;MC&#039;,&#039;MD&#039;,&#039;MG&#039;,&#039;MH&#039;,&#039;MK&#039;,&#039;ML&#039;,&#039;MM&#039;,&#039;MN&#039;,&#039;MO&#039;,&#039;MP&#039;,&#039;MQ&#039;,&#039;MR&#039;,&#039;MS&#039;,&#039;MT&#039;,&#039;MU&#039;,&#039;MV&#039;,&#039;MW&#039;,&#039;MX&#039;,&#039;MY&#039;,&#039;MZ&#039;,&#039;NA&#039;,&#039;NC&#039;,&#039;NE&#039;,&#039;NF&#039;,&#039;NG&#039;,&#039;NI&#039;,&#039;NL&#039;,&#039;NO&#039;,&#039;NP&#039;,&#039;NR&#039;,&#039;NU&#039;,&#039;NZ&#039;,&#039;OM&#039;,&#039;PA&#039;,&#039;PE&#039;,&#039;PF&#039;,&#039;PG&#039;,&#039;PH&#039;,&#039;PK&#039;,&#039;PL&#039;,&#039;PM&#039;,&#039;PN&#039;,&#039;PR&#039;,&#039;PS&#039;,&#039;PT&#039;,&#039;PW&#039;,&#039;PY&#039;,&#039;QA&#039;,&#039;RE&#039;,&#039;RO&#039;,&#039;RU&#039;,&#039;RW&#039;,&#039;SA&#039;,&#039;SB&#039;,&#039;SC&#039;,&#039;SD&#039;,&#039;SE&#039;,&#039;SG&#039;,&#039;SH&#039;,&#039;SI&#039;,&#039;SJ&#039;,&#039;SK&#039;,&#039;SL&#039;,&#039;SM&#039;,&#039;SN&#039;,&#039;SO&#039;,&#039;SR&#039;,&#039;ST&#039;,&#039;SV&#039;,&#039;SY&#039;,&#039;SZ&#039;,&#039;TC&#039;,&#039;TD&#039;,&#039;TF&#039;,&#039;TG&#039;,&#039;TH&#039;,&#039;TJ&#039;,&#039;TK&#039;,&#039;TM&#039;,&#039;TN&#039;,&#039;TO&#039;,&#039;TP&#039;,&#039;TR&#039;,&#039;TT&#039;,&#039;TV&#039;,&#039;TW&#039;,&#039;TZ&#039;,&#039;UA&#039;,&#039;UG&#039;,&#039;UM&#039;,&#039;US&#039;,&#039;UY&#039;,&#039;UZ&#039;,&#039;VA&#039;,&#039;VC&#039;,&#039;VE&#039;,&#039;VG&#039;,&#039;VI&#039;,&#039;VN&#039;,&#039;VU&#039;,&#039;WF&#039;,&#039;WS&#039;,&#039;YE&#039;,&#039;YT&#039;,&#039;YU&#039;,&#039;ZA&#039;,&#039;ZM&#039;,&#039;ZR&#039;,&#039;ZW&#039;,&#039;A1&#039;,&#039;A2&#039;)&lt;br /&gt;
    __CODE3S = (&#039;--&#039;,&#039;AP&#039;,&#039;EU&#039;,&#039;AND&#039;,&#039;ARE&#039;,&#039;AFG&#039;,&#039;ATG&#039;,&#039;AIA&#039;,&#039;ALB&#039;,&#039;ARM&#039;,&#039;ANT&#039;,&#039;AGO&#039;,&#039;AQ&#039;,&#039;ARG&#039;,&#039;ASM&#039;,&#039;AUT&#039;,&#039;AUS&#039;,&#039;ABW&#039;,&#039;AZE&#039;,&#039;BIH&#039;,&#039;BRB&#039;,&#039;BGD&#039;,&#039;BEL&#039;,&#039;BFA&#039;,&#039;BGR&#039;,&#039;BHR&#039;,&#039;BDI&#039;,&#039;BEN&#039;,&#039;BMU&#039;,&#039;BRN&#039;,&#039;BOL&#039;,&#039;BRA&#039;,&#039;BHS&#039;,&#039;BTN&#039;,&#039;BV&#039;,&#039;BWA&#039;,&#039;BLR&#039;,&#039;BLZ&#039;,&#039;CAN&#039;,&#039;CC&#039;,&#039;COD&#039;,&#039;CAF&#039;,&#039;COG&#039;,&#039;CHE&#039;,&#039;CIV&#039;,&#039;COK&#039;,&#039;CHL&#039;,&#039;CMR&#039;,&#039;CHN&#039;,&#039;COL&#039;,&#039;CRI&#039;,&#039;CUB&#039;,&#039;CPV&#039;,&#039;CX&#039;,&#039;CYP&#039;,&#039;CZE&#039;,&#039;DEU&#039;,&#039;DJI&#039;,&#039;DNK&#039;,&#039;DMA&#039;,&#039;DOM&#039;,&#039;DZA&#039;,&#039;ECU&#039;,&#039;EST&#039;,&#039;EGY&#039;,&#039;ESH&#039;,&#039;ERI&#039;,&#039;ESP&#039;,&#039;ETH&#039;,&#039;FIN&#039;,&#039;FJI&#039;,&#039;FLK&#039;,&#039;FSM&#039;,&#039;FRO&#039;,&#039;FRA&#039;,&#039;FX&#039;,&#039;GAB&#039;,&#039;GBR&#039;,&#039;GRD&#039;,&#039;GEO&#039;,&#039;GUF&#039;,&#039;GHA&#039;,&#039;GIB&#039;,&#039;GRL&#039;,&#039;GMB&#039;,&#039;GIN&#039;,&#039;GLP&#039;,&#039;GNQ&#039;,&#039;GRC&#039;,&#039;GS&#039;,&#039;GTM&#039;,&#039;GUM&#039;,&#039;GNB&#039;,&#039;GUY&#039;,&#039;HKG&#039;,&#039;HM&#039;,&#039;HND&#039;,&#039;HRV&#039;,&#039;HTI&#039;,&#039;HUN&#039;,&#039;IDN&#039;,&#039;IRL&#039;,&#039;ISR&#039;,&#039;IND&#039;,&#039;IO&#039;,&#039;IRQ&#039;,&#039;IRN&#039;,&#039;ISL&#039;,&#039;ITA&#039;,&#039;JAM&#039;,&#039;JOR&#039;,&#039;JPN&#039;,&#039;KEN&#039;,&#039;KGZ&#039;,&#039;KHM&#039;,&#039;KIR&#039;,&#039;COM&#039;,&#039;KNA&#039;,&#039;PRK&#039;,&#039;KOR&#039;,&#039;KWT&#039;,&#039;CYM&#039;,&#039;KAZ&#039;,&#039;LAO&#039;,&#039;LBN&#039;,&#039;LCA&#039;,&#039;LIE&#039;,&#039;LKA&#039;,&#039;LBR&#039;,&#039;LSO&#039;,&#039;LTU&#039;,&#039;LUX&#039;,&#039;LVA&#039;,&#039;LBY&#039;,&#039;MAR&#039;,&#039;MCO&#039;,&#039;MDA&#039;,&#039;MDG&#039;,&#039;MHL&#039;,&#039;MKD&#039;,&#039;MLI&#039;,&#039;MMR&#039;,&#039;MNG&#039;,&#039;MAC&#039;,&#039;MNP&#039;,&#039;MTQ&#039;,&#039;MRT&#039;,&#039;MSR&#039;,&#039;MLT&#039;,&#039;MUS&#039;,&#039;MDV&#039;,&#039;MWI&#039;,&#039;MEX&#039;,&#039;MYS&#039;,&#039;MOZ&#039;,&#039;NAM&#039;,&#039;NCL&#039;,&#039;NER&#039;,&#039;NFK&#039;,&#039;NGA&#039;,&#039;NIC&#039;,&#039;NLD&#039;,&#039;NOR&#039;,&#039;NPL&#039;,&#039;NRU&#039;,&#039;NIU&#039;,&#039;NZL&#039;,&#039;OMN&#039;,&#039;PAN&#039;,&#039;PER&#039;,&#039;PYF&#039;,&#039;PNG&#039;,&#039;PHL&#039;,&#039;PAK&#039;,&#039;POL&#039;,&#039;SPM&#039;,&#039;PCN&#039;,&#039;PRI&#039;,&#039;PSE&#039;,&#039;PRT&#039;,&#039;PLW&#039;,&#039;PRY&#039;,&#039;QAT&#039;,&#039;REU&#039;,&#039;ROM&#039;,&#039;RUS&#039;,&#039;RWA&#039;,&#039;SAU&#039;,&#039;SLB&#039;,&#039;SYC&#039;,&#039;SDN&#039;,&#039;SWE&#039;,&#039;SGP&#039;,&#039;SHN&#039;,&#039;SVN&#039;,&#039;SJM&#039;,&#039;SVK&#039;,&#039;SLE&#039;,&#039;SMR&#039;,&#039;SEN&#039;,&#039;SOM&#039;,&#039;SUR&#039;,&#039;STP&#039;,&#039;SLV&#039;,&#039;SYR&#039;,&#039;SWZ&#039;,&#039;TCA&#039;,&#039;TCD&#039;,&#039;TF&#039;,&#039;TGO&#039;,&#039;THA&#039;,&#039;TJK&#039;,&#039;TKL&#039;,&#039;TLS&#039;,&#039;TKM&#039;,&#039;TUN&#039;,&#039;TON&#039;,&#039;TUR&#039;,&#039;TTO&#039;,&#039;TUV&#039;,&#039;TWN&#039;,&#039;TZA&#039;,&#039;UKR&#039;,&#039;UGA&#039;,&#039;UM&#039;,&#039;USA&#039;,&#039;URY&#039;,&#039;UZB&#039;,&#039;VAT&#039;,&#039;VCT&#039;,&#039;VEN&#039;,&#039;VGB&#039;,&#039;VIR&#039;,&#039;VNM&#039;,&#039;VUT&#039;,&#039;WLF&#039;,&#039;WSM&#039;,&#039;YEM&#039;,&#039;YT&#039;,&#039;YUG&#039;,&#039;ZAF&#039;,&#039;ZMB&#039;,&#039;ZR&#039;,&#039;ZWE&#039;,&#039;A1&#039;,&#039;A2&#039;)&lt;br /&gt;
    __NAMES = (&amp;quot;--&amp;quot;,&amp;quot;Asia/Pacific Region&amp;quot;,&amp;quot;Europe&amp;quot;,&amp;quot;Andorra&amp;quot;,&amp;quot;United Arab Emirates&amp;quot;,&amp;quot;Afghanistan&amp;quot;,&amp;quot;Antigua and Barbuda&amp;quot;,&amp;quot;Anguilla&amp;quot;,&amp;quot;Albania&amp;quot;,&amp;quot;Armenia&amp;quot;,&amp;quot;Netherlands Antilles&amp;quot;,&amp;quot;Angola&amp;quot;,&amp;quot;Antarctica&amp;quot;,&amp;quot;Argentina&amp;quot;,&amp;quot;American Samoa&amp;quot;,&amp;quot;Austria&amp;quot;,&amp;quot;Australia&amp;quot;,&amp;quot;Aruba&amp;quot;,&amp;quot;Azerbaijan&amp;quot;,&amp;quot;Bosnia and Herzegovina&amp;quot;,&amp;quot;Barbados&amp;quot;,&amp;quot;Bangladesh&amp;quot;,&amp;quot;Belgium&amp;quot;,&amp;quot;Burkina Faso&amp;quot;,&amp;quot;Bulgaria&amp;quot;,&amp;quot;Bahrain&amp;quot;,&amp;quot;Burundi&amp;quot;,&amp;quot;Benin&amp;quot;,&amp;quot;Bermuda&amp;quot;,&amp;quot;Brunei Darussalam&amp;quot;,&amp;quot;Bolivia&amp;quot;,&amp;quot;Brazil&amp;quot;,&amp;quot;Bahamas&amp;quot;,&amp;quot;Bhutan&amp;quot;,&amp;quot;Bouvet Island&amp;quot;,&amp;quot;Botswana&amp;quot;,&amp;quot;Belarus&amp;quot;,&amp;quot;Belize&amp;quot;,&amp;quot;Canada&amp;quot;,&amp;quot;Cocos (Keeling) Islands&amp;quot;,&amp;quot;Congo, The Democratic Republic of the&amp;quot;,&amp;quot;Central African Republic&amp;quot;,&amp;quot;Congo&amp;quot;,&amp;quot;Switzerland&amp;quot;,&amp;quot;Cote D&#039;Ivoire&amp;quot;,&amp;quot;Cook Islands&amp;quot;,&amp;quot;Chile&amp;quot;,&amp;quot;Cameroon&amp;quot;,&amp;quot;China&amp;quot;,&amp;quot;Colombia&amp;quot;,&amp;quot;Costa Rica&amp;quot;,&amp;quot;Cuba&amp;quot;,&amp;quot;Cape Verde&amp;quot;,&amp;quot;Christmas Island&amp;quot;,&amp;quot;Cyprus&amp;quot;,&amp;quot;Czech Republic&amp;quot;,&amp;quot;Germany&amp;quot;,&amp;quot;Djibouti&amp;quot;,&amp;quot;Denmark&amp;quot;,&amp;quot;Dominica&amp;quot;,&amp;quot;Dominican Republic&amp;quot;,&amp;quot;Algeria&amp;quot;,&amp;quot;Ecuador&amp;quot;,&amp;quot;Estonia&amp;quot;,&amp;quot;Egypt&amp;quot;,&amp;quot;Western Sahara&amp;quot;,&amp;quot;Eritrea&amp;quot;,&amp;quot;Spain&amp;quot;,&amp;quot;Ethiopia&amp;quot;,&amp;quot;Finland&amp;quot;,&amp;quot;Fiji&amp;quot;,&amp;quot;Falkland Islands (Malvinas)&amp;quot;,&amp;quot;Micronesia, Federated States of&amp;quot;,&amp;quot;Faroe Islands&amp;quot;,&amp;quot;France&amp;quot;,&amp;quot;France, Metropolitan&amp;quot;,&amp;quot;Gabon&amp;quot;,&amp;quot;United Kingdom&amp;quot;,&amp;quot;Grenada&amp;quot;,&amp;quot;Georgia&amp;quot;,&amp;quot;French Guiana&amp;quot;,&amp;quot;Ghana&amp;quot;,&amp;quot;Gibraltar&amp;quot;,&amp;quot;Greenland&amp;quot;,&amp;quot;Gambia&amp;quot;,&amp;quot;Guinea&amp;quot;,&amp;quot;Guadeloupe&amp;quot;,&amp;quot;Equatorial Guinea&amp;quot;,&amp;quot;Greece&amp;quot;,&amp;quot;South Georgia and the South Sandwich Islands&amp;quot;,&amp;quot;Guatemala&amp;quot;,&amp;quot;Guam&amp;quot;,&amp;quot;Guinea-Bissau&amp;quot;,&amp;quot;Guyana&amp;quot;,&amp;quot;Hong Kong&amp;quot;,&amp;quot;Heard Island and McDonald Islands&amp;quot;,&amp;quot;Honduras&amp;quot;,&amp;quot;Croatia&amp;quot;,&amp;quot;Haiti&amp;quot;,&amp;quot;Hungary&amp;quot;,&amp;quot;Indonesia&amp;quot;,&amp;quot;Ireland&amp;quot;,&amp;quot;Israel&amp;quot;,&amp;quot;India&amp;quot;,&amp;quot;British Indian Ocean Territory&amp;quot;,&amp;quot;Iraq&amp;quot;,&amp;quot;Iran, Islamic Republic of&amp;quot;,&amp;quot;Iceland&amp;quot;,&amp;quot;Italy&amp;quot;,&amp;quot;Jamaica&amp;quot;,&amp;quot;Jordan&amp;quot;,&amp;quot;Japan&amp;quot;,&amp;quot;Kenya&amp;quot;,&amp;quot;Kyrgyzstan&amp;quot;,&amp;quot;Cambodia&amp;quot;,&amp;quot;Kiribati&amp;quot;,&amp;quot;Comoros&amp;quot;,&amp;quot;Saint Kitts and Nevis&amp;quot;,&lt;br /&gt;
&amp;quot;Korea, Democratic People&#039;s Republic of&amp;quot;,&amp;quot;Korea, Republic of&amp;quot;,&amp;quot;Kuwait&amp;quot;,&amp;quot;Cayman Islands&amp;quot;,&amp;quot;Kazakhstan&amp;quot;,&amp;quot;Lao People&#039;s Democratic Republic&amp;quot;,&amp;quot;Lebanon&amp;quot;,&amp;quot;Saint Lucia&amp;quot;,&amp;quot;Liechtenstein&amp;quot;,&amp;quot;Sri Lanka&amp;quot;,&amp;quot;Liberia&amp;quot;,&amp;quot;Lesotho&amp;quot;,&amp;quot;Lithuania&amp;quot;,&amp;quot;Luxembourg&amp;quot;,&amp;quot;Latvia&amp;quot;,&amp;quot;Libyan Arab Jamahiriya&amp;quot;,&amp;quot;Morocco&amp;quot;,&amp;quot;Monaco&amp;quot;,&amp;quot;Moldova, Republic of&amp;quot;,&amp;quot;Madagascar&amp;quot;,&amp;quot;Marshall Islands&amp;quot;,&amp;quot;Macedonia&amp;quot;,&amp;quot;Mali&amp;quot;,&amp;quot;Myanmar&amp;quot;,&amp;quot;Mongolia&amp;quot;,&amp;quot;Macau&amp;quot;,&amp;quot;Northern Mariana Islands&amp;quot;,&amp;quot;Martinique&amp;quot;,&amp;quot;Mauritania&amp;quot;,&amp;quot;Montserrat&amp;quot;,&amp;quot;Malta&amp;quot;,&amp;quot;Mauritius&amp;quot;,&amp;quot;Maldives&amp;quot;,&amp;quot;Malawi&amp;quot;,&amp;quot;Mexico&amp;quot;,&amp;quot;Malaysia&amp;quot;,&amp;quot;Mozambique&amp;quot;,&amp;quot;Namibia&amp;quot;,&amp;quot;New Caledonia&amp;quot;,&amp;quot;Niger&amp;quot;,&amp;quot;Norfolk Island&amp;quot;,&amp;quot;Nigeria&amp;quot;,&amp;quot;Nicaragua&amp;quot;,&amp;quot;Netherlands&amp;quot;,&amp;quot;Norway&amp;quot;,&amp;quot;Nepal&amp;quot;,&amp;quot;Nauru&amp;quot;,&amp;quot;Niue&amp;quot;,&amp;quot;New Zealand&amp;quot;,&amp;quot;Oman&amp;quot;,&amp;quot;Panama&amp;quot;,&amp;quot;Peru&amp;quot;,&amp;quot;French Polynesia&amp;quot;,&amp;quot;Papua New Guinea&amp;quot;,&amp;quot;Philippines&amp;quot;,&amp;quot;Pakistan&amp;quot;,&amp;quot;Poland&amp;quot;,&amp;quot;Saint Pierre and Miquelon&amp;quot;,&amp;quot;Pitcairn Islands&amp;quot;,&amp;quot;Puerto Rico&amp;quot;,&amp;quot;Palestinian Territory, Occupied&amp;quot;,&amp;quot;Portugal&amp;quot;,&amp;quot;Palau&amp;quot;,&amp;quot;Paraguay&amp;quot;,&amp;quot;Qatar&amp;quot;,&amp;quot;Reunion&amp;quot;,&amp;quot;Romania&amp;quot;,&amp;quot;Russian Federation&amp;quot;,&amp;quot;Rwanda&amp;quot;,&amp;quot;Saudi Arabia&amp;quot;,&amp;quot;Solomon Islands&amp;quot;,&amp;quot;Seychelles&amp;quot;,&amp;quot;Sudan&amp;quot;,&amp;quot;Sweden&amp;quot;,&amp;quot;Singapore&amp;quot;,&amp;quot;Saint Helena&amp;quot;,&amp;quot;Slovenia&amp;quot;,&amp;quot;Svalbard and Jan Mayen&amp;quot;,&amp;quot;Slovakia&amp;quot;,&amp;quot;Sierra Leone&amp;quot;,&amp;quot;San Marino&amp;quot;,&amp;quot;Senegal&amp;quot;,&amp;quot;Somalia&amp;quot;,&amp;quot;Suriname&amp;quot;,&amp;quot;Sao Tome and Principe&amp;quot;,&amp;quot;El Salvador&amp;quot;,&amp;quot;Syrian Arab Republic&amp;quot;,&amp;quot;Swaziland&amp;quot;,&amp;quot;Turks and Caicos Islands&amp;quot;,&amp;quot;Chad&amp;quot;,&amp;quot;French Southern Territories&amp;quot;,&amp;quot;Togo&amp;quot;,&amp;quot;Thailand&amp;quot;,&amp;quot;Tajikistan&amp;quot;,&amp;quot;Tokelau&amp;quot;,&amp;quot;Turkmenistan&amp;quot;,&amp;quot;Tunisia&amp;quot;,&amp;quot;Tonga&amp;quot;,&amp;quot;East Timor&amp;quot;,&amp;quot;Turkey&amp;quot;,&amp;quot;Trinidad and Tobago&amp;quot;,&amp;quot;Tuvalu&amp;quot;,&amp;quot;Taiwan&amp;quot;,&amp;quot;Tanzania, United Republic of&amp;quot;,&amp;quot;Ukraine&amp;quot;,&amp;quot;Uganda&amp;quot;,&amp;quot;United States Minor Outlying Islands&amp;quot;,&amp;quot;United States&amp;quot;,&amp;quot;Uruguay&amp;quot;,&amp;quot;Uzbekistan&amp;quot;,&amp;quot;Holy See (Vatican City State)&amp;quot;,&amp;quot;Saint Vincent and the Grenadines&amp;quot;,&amp;quot;Venezuela&amp;quot;,&amp;quot;Virgin Islands, British&amp;quot;,&amp;quot;Virgin Islands, U.S.&amp;quot;,&amp;quot;Vietnam&amp;quot;,&amp;quot;Vanuatu&amp;quot;,&amp;quot;Wallis and Futuna&amp;quot;,&amp;quot;Samoa&amp;quot;,&amp;quot;Yemen&amp;quot;,&amp;quot;Mayotte&amp;quot;,&amp;quot;Yugoslavia&amp;quot;,&amp;quot;South Africa&amp;quot;,&amp;quot;Zambia&amp;quot;,&amp;quot;Zaire&amp;quot;,&amp;quot;Zimbabwe&amp;quot;,&lt;br /&gt;
&amp;quot;Anonymous Proxy&amp;quot;,&amp;quot;Satellite Provider&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    __RE_IP_DOTTED_FORM = re.compile(&amp;quot;^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    GEOIP_STANDARD = 0 # TODO&lt;br /&gt;
&lt;br /&gt;
    def addr_to_num(ip_address):&lt;br /&gt;
        &#039;&#039;&#039;Convert IP-address to number.&#039;&#039;&#039;&lt;br /&gt;
        # a = [int(s) for s in re.split(&#039;\.&#039;, ip_address)]&lt;br /&gt;
        a = map(int, re.split(&#039;\.&#039;, ip_address))&lt;br /&gt;
        return a[0] * 16777216L + a[1] * 65536L + a[2] * 256L + a[3]&lt;br /&gt;
&lt;br /&gt;
    def open(db_file, flags):&lt;br /&gt;
        &#039;&#039;&#039;Create a new GeoIP object.&#039;&#039;&#039;&lt;br /&gt;
        gi = GeoIP()&lt;br /&gt;
        gi.db_file = db_file&lt;br /&gt;
        gi.flags = flags # TODO&lt;br /&gt;
        gi.fh = open(db_file, &#039;rb&#039;)&lt;br /&gt;
        gi.databaseType = GeoIP.__GEOIP_COUNTRY_EDITION # TODO&lt;br /&gt;
        gi.record_length = GeoIP.__STANDARD_RECORD_LENGTH # TODO&lt;br /&gt;
        gi.databaseSegments = GeoIP.__GEOIP_COUNTRY_BEGIN # TODO&lt;br /&gt;
        return gi&lt;br /&gt;
&lt;br /&gt;
    def new(flags):&lt;br /&gt;
        &#039;&#039;&#039;Create a new GeoIP object.&#039;&#039;&#039;&lt;br /&gt;
        return GeoIP.open(&#039;/usr/local/share/GeoIP/GeoIP.dat&#039;, flags)&lt;br /&gt;
&lt;br /&gt;
    def __seek_country(self, ipnum):&lt;br /&gt;
        &#039;&#039;&#039;Seek GeoIP data file to find country id.&#039;&#039;&#039;&lt;br /&gt;
        fh = self.fh&lt;br /&gt;
        record_length = self.record_length&lt;br /&gt;
        databaseSegments = self.databaseSegments&lt;br /&gt;
        offset = 0&lt;br /&gt;
        x0 = -1&lt;br /&gt;
        x1 = -1&lt;br /&gt;
        for depth in nreverse(range(32)):&lt;br /&gt;
            fh.seek(offset * 2 * record_length, 0)&lt;br /&gt;
            x0 = fh.read(record_length)&lt;br /&gt;
            x1 = fh.read(record_length)&lt;br /&gt;
            x0, = struct.unpack(&amp;quot;&amp;lt;1l&amp;quot;, x0 + &amp;quot;\0&amp;quot;)&lt;br /&gt;
            x1, = struct.unpack(&amp;quot;&amp;lt;1l&amp;quot;, x1 + &amp;quot;\0&amp;quot;)&lt;br /&gt;
            if ipnum &amp;amp; (1L &amp;lt;&amp;lt; depth):&lt;br /&gt;
                if x1 &amp;gt;= databaseSegments:&lt;br /&gt;
                    return x1&lt;br /&gt;
                offset = x1&lt;br /&gt;
            else:&lt;br /&gt;
                if x0 &amp;gt;= databaseSegments:&lt;br /&gt;
                    return x0&lt;br /&gt;
                offset = x0&lt;br /&gt;
        raise Exception(&#039;Error Traversing Database for ipnum = %d - Perhaps database is corrupt?&#039; % ipnum) # TODO&lt;br /&gt;
&lt;br /&gt;
    def id_by_addr(self, ip_address):&lt;br /&gt;
        &#039;&#039;&#039;Find country id by IP-address.&#039;&#039;&#039;&lt;br /&gt;
        if self.__RE_IP_DOTTED_FORM.match(ip_address):&lt;br /&gt;
            return self.__seek_country(self.addr_to_num(ip_address)) - self.__GEOIP_COUNTRY_BEGIN&lt;br /&gt;
        else:&lt;br /&gt;
            return 0&lt;br /&gt;
&lt;br /&gt;
    def id_to_country_code(id):&lt;br /&gt;
        &#039;&#039;&#039;Convert country id to country code.&#039;&#039;&#039;&lt;br /&gt;
        return GeoIP.__COUNTRIES[id]&lt;br /&gt;
&lt;br /&gt;
    def id_to_country_code3(id):&lt;br /&gt;
        &#039;&#039;&#039;Convert country id to country code.&#039;&#039;&#039;&lt;br /&gt;
        return GeoIP.__CODE3S[id]&lt;br /&gt;
&lt;br /&gt;
    def id_to_country_name(id):&lt;br /&gt;
        &#039;&#039;&#039;Convert country id to country code.&#039;&#039;&#039;&lt;br /&gt;
        return GeoIP.__NAMES[id]&lt;br /&gt;
&lt;br /&gt;
    def country_code_by_addr(self, ip_address):&lt;br /&gt;
        &#039;&#039;&#039;Find country code by IP-address.&#039;&#039;&#039;&lt;br /&gt;
        return GeoIP.id_to_country_code(self.id_by_addr(ip_address))&lt;br /&gt;
&lt;br /&gt;
    def country_code3_by_addr(self, ip_address):&lt;br /&gt;
        &#039;&#039;&#039;Find country code3 by IP-address.&#039;&#039;&#039;&lt;br /&gt;
        return GeoIP.id_to_country_code3(self.id_by_addr(ip_address))&lt;br /&gt;
&lt;br /&gt;
    def country_name_by_addr(self, ip_address):&lt;br /&gt;
        &#039;&#039;&#039;Find country name by IP-address.&#039;&#039;&#039;&lt;br /&gt;
        return GeoIP.id_to_country_name(self.id_by_addr(ip_address))&lt;br /&gt;
&lt;br /&gt;
    addr_to_num = staticmethod(addr_to_num)&lt;br /&gt;
    open = staticmethod(open)&lt;br /&gt;
    new = staticmethod(new)&lt;br /&gt;
    id_to_country_code = staticmethod(id_to_country_code)&lt;br /&gt;
    id_to_country_code3 = staticmethod(id_to_country_code3)&lt;br /&gt;
    id_to_country_name = staticmethod(id_to_country_name)&lt;br /&gt;
&lt;br /&gt;
if &#039;__main__&#039; == __name__:&lt;br /&gt;
    import sys&lt;br /&gt;
    import string&lt;br /&gt;
&lt;br /&gt;
    argc = len(sys.argv)&lt;br /&gt;
    gi = None&lt;br /&gt;
    if 2 == argc:&lt;br /&gt;
        gi = GeoIP.new(GeoIP.GEOIP_STANDARD)&lt;br /&gt;
    elif 3 == argc:&lt;br /&gt;
        gi = GeoIP.open(sys.argv[2], GeoIP.GEOIP_STANDARD)&lt;br /&gt;
    else:&lt;br /&gt;
        print &amp;quot;Usage:\n  %s &amp;lt;ipaddress&amp;gt; [geoipdatafile]&amp;quot; % sys.argv[0]&lt;br /&gt;
        sys.exit(1)&lt;br /&gt;
&lt;br /&gt;
    ip = sys.argv[1]&lt;br /&gt;
    id = str(gi.id_by_addr(ip))&lt;br /&gt;
    code = gi.country_code_by_addr(ip)&lt;br /&gt;
    code3 = gi.country_code3_by_addr(ip)&lt;br /&gt;
    name = gi.country_name_by_addr(ip)&lt;br /&gt;
&lt;br /&gt;
    print string.join([&#039;ipaddress&#039;, &#039;id&#039;, &#039;code&#039;, &#039;code3&#039;, &#039;name&#039;], &amp;quot;\t&amp;quot;)&lt;br /&gt;
    print string.join([ip, id, code, code3, name], &amp;quot;\t&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Pireax</name></author>
	</entry>
	<entry>
		<id>https://bf2tech.uturista.pt/index.php?title=Scripts:ReserveSlots&amp;diff=100</id>
		<title>Scripts:ReserveSlots</title>
		<link rel="alternate" type="text/html" href="https://bf2tech.uturista.pt/index.php?title=Scripts:ReserveSlots&amp;diff=100"/>
		<updated>2018-06-22T15:23:47Z</updated>

		<summary type="html">&lt;p&gt;Pireax: Created page with &amp;quot;This will open a file &amp;quot;knownplayers.txt&amp;quot; and use it to maintain a list of players who should get priority.  To use it, log in with rcon and type &amp;quot;rcon addPlayer playerName&amp;quot; or...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This will open a file &amp;quot;knownplayers.txt&amp;quot; and use it to maintain a list of players who should get priority.&lt;br /&gt;
&lt;br /&gt;
To use it, log in with rcon and type &amp;quot;rcon addPlayer playerName&amp;quot; or &amp;quot;rcon removePlayer playerName&amp;quot;. You can change the server mode with &amp;quot;rcon changeMode mode&amp;quot; where mode is public, private or semiprivate. Public is anything goes, private is list only and semiprivate let&#039;s anyone join but will kick players off the list to make room for players on the list if the server gets full. Semiprivate will only kick commanders as a last resort.&lt;br /&gt;
&lt;br /&gt;
There&#039;s also &amp;quot;rcon numFromList&amp;quot; to get the number of people on the server who are on the list. &amp;quot;rcon isOnList playername&amp;quot; is obvious, and &amp;quot;rcon currMode&amp;quot; will tell you what mode the server is in.&lt;br /&gt;
&lt;br /&gt;
Enjoy!&lt;br /&gt;
&lt;br /&gt;
Call this file kickoutsiders.py and put it in your standard_admin folder along with a knownplayers.txt file.&lt;br /&gt;
&lt;br /&gt;
kickoutsiders.py:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
import host&lt;br /&gt;
import bf2&lt;br /&gt;
&lt;br /&gt;
scriptName = &#039;Doc &amp;amp; sirSolarius Kicker v1.7&#039;&lt;br /&gt;
fileName = &#039;admin/standard_admin/knownplayers.txt&#039;&lt;br /&gt;
knownPlayers = []&lt;br /&gt;
mode = 1&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def init():&lt;br /&gt;
    print &amp;quot;Starting &amp;quot; + scriptName&lt;br /&gt;
    global knownPlayers, fileName&lt;br /&gt;
    playersFile = file(fileName, &#039;r&#039;)&lt;br /&gt;
    for i in playersFile:&lt;br /&gt;
        knownPlayers.append(i.rstrip())&lt;br /&gt;
    playersFile.close()&lt;br /&gt;
    print knownPlayers&lt;br /&gt;
    host.registerHandler(&#039;PlayerConnect&#039;, onPlayerConnect, 1)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def onPlayerConnect(aPlayer):&lt;br /&gt;
    global knownPlayers, mode&lt;br /&gt;
   &lt;br /&gt;
    # private&lt;br /&gt;
    if mode == 0:&lt;br /&gt;
        if not aPlayer.getName() in knownPlayers:&lt;br /&gt;
            host.rcon_invoke(&#039;game.sayAll &amp;quot;&#039; + scriptName + &#039;: Player &#039; + aPlayer.getName() + &#039; was not on the list!&#039; + &#039;&amp;quot;&#039;)&lt;br /&gt;
            host.rcon_invoke(&#039;admin.kickPlayer &#039; + str(aPlayer.index))&lt;br /&gt;
   &lt;br /&gt;
    # semiprivate&lt;br /&gt;
    elif mode == 1:&lt;br /&gt;
        #if we&#039;re at capacity (new person fills our extra spot)&lt;br /&gt;
        if bf2.playerManager.getNumberOfPlayers() ==  bf2.serverSettings.getMaxPlayers():&lt;br /&gt;
            # if he&#039;s not on the list, put him back where he came from&lt;br /&gt;
            if not aPlayer.getName() in knownPlayers:&lt;br /&gt;
                host.rcon_invoke(&#039;game.sayAll &amp;quot;&#039; + scriptName + &#039;: Player &#039; + aPlayer.getName() + &#039; kicked: no room for people off the list!&#039; + &#039;&amp;quot;&#039;)&lt;br /&gt;
                host.rcon_invoke(&#039;admin.kickPlayer &#039; + str(aPlayer.index))&lt;br /&gt;
                return&lt;br /&gt;
            # he&#039;s on the list: kick someone who isn&#039;t&lt;br /&gt;
            else:&lt;br /&gt;
                currPlayers=bf2.playerManager.getPlayers()&lt;br /&gt;
                foundCommander=0&lt;br /&gt;
                commander=aPlayer&lt;br /&gt;
                for i in currPlayers:&lt;br /&gt;
                    # if we found someone to toss out&lt;br /&gt;
                    if not i.getName() in knownPlayers:&lt;br /&gt;
                        # if he&#039;s the commander, try to find someone else&lt;br /&gt;
                        if i.isCommander():&lt;br /&gt;
                            commander=i&lt;br /&gt;
                            foundCommander=1&lt;br /&gt;
                        else:&lt;br /&gt;
                            host.rcon_invoke(&#039;game.sayAll &amp;quot;&#039; + scriptName + &#039;: Player &#039; + i.getName() + &#039; kicked for &#039; + aPlayer.getName() + &#039;&amp;quot;&#039;)&lt;br /&gt;
                            host.rcon_invoke(&#039;admin.kickPlayer &#039; + str(i.index))&lt;br /&gt;
                            return&lt;br /&gt;
                # if we checked everyone and only the commander remains... bye bye&lt;br /&gt;
                if foundCommander == 1:&lt;br /&gt;
                    host.rcon_invoke(&#039;game.sayAll &amp;quot;&#039; + scriptName + &#039;: Player &#039; + commander.getName() + &#039; kicked for &#039; + aPlayer.getName() + &#039;&amp;quot;&#039;)&lt;br /&gt;
                    host.rcon_invoke(&#039;admin.kickPlayer &#039; + str(commander.index))&lt;br /&gt;
                else:&lt;br /&gt;
                    # no one to kick =(&lt;br /&gt;
                    #host.rcon_invoke(&#039;game.sayAll &amp;quot;&#039; + scriptName + &#039;: Player &#039; + aPlayer.getName() + &#039; kicked: no room even for people on the list!&#039; + &#039;&amp;quot;&#039;)&lt;br /&gt;
                    #host.rcon_invoke(&#039;admin.kickPlayer &#039; + str(aPlayer.index))&lt;br /&gt;
                    return&lt;br /&gt;
&lt;br /&gt;
def changeMode(m):&lt;br /&gt;
    global mode, knownPlayers, scriptName&lt;br /&gt;
    if m == &#039;private&#039;:&lt;br /&gt;
        host.rcon_invoke(&#039;game.sayAll &amp;quot;&#039; + scriptName + &#039;: Changing to private mode.  Flushing the undesirables!&amp;quot;&#039;)&lt;br /&gt;
        currPlayers=bf2.playerManager.getPlayers()&lt;br /&gt;
        for i in currPlayers:&lt;br /&gt;
            if not i.getName() in knownPlayers:&lt;br /&gt;
                host.rcon_invoke(&#039;admin.kickPlayer &#039; + str(i.index))&lt;br /&gt;
               &lt;br /&gt;
        mode=0&lt;br /&gt;
    elif m == &#039;semiprivate&#039;:&lt;br /&gt;
        host.rcon_invoke(&#039;game.sayAll &amp;quot;&#039; + scriptName + &#039;: Changing to semiprivate mode.  Bring on some asshats!&amp;quot;&#039;)&lt;br /&gt;
        mode=1&lt;br /&gt;
    else:&lt;br /&gt;
        host.rcon_invoke(&#039;game.sayAll &amp;quot;&#039; + scriptName + &#039;: Changing to public mode.  Bring on the asshats!&amp;quot;&#039;)&lt;br /&gt;
        mode=2&lt;br /&gt;
   &lt;br /&gt;
def addPlayerToList(aPlayerName):&lt;br /&gt;
    global fileName, knownPlayers&lt;br /&gt;
    if aPlayerName in knownPlayers:&lt;br /&gt;
        print &#039;User already in list!&#039;&lt;br /&gt;
        return&lt;br /&gt;
    playersFile = file(fileName, &#039;a&#039;)&lt;br /&gt;
    playersFile.write(aPlayerName+&#039;\n&#039;)&lt;br /&gt;
    knownPlayers.append(aPlayerName)&lt;br /&gt;
    print &#039;User added to list.&#039;&lt;br /&gt;
   &lt;br /&gt;
def writeMode(ctx):&lt;br /&gt;
    global mode&lt;br /&gt;
    if (mode == 0):&lt;br /&gt;
        ctx.write(&#039;The current mode is private.&#039;)&lt;br /&gt;
    elif(mode == 1):&lt;br /&gt;
        ctx.write(&#039;The current mode is semiprivate.&#039;)&lt;br /&gt;
    else:&lt;br /&gt;
        ctx.write(&#039;The current mode is public.&#039;)&lt;br /&gt;
&lt;br /&gt;
def writeNumList(ctx):&lt;br /&gt;
    global knownPlayers&lt;br /&gt;
    playerCount=0&lt;br /&gt;
    currPlayers=bf2.playerManager.getPlayers()&lt;br /&gt;
    for i in currPlayers:&lt;br /&gt;
        if i.getName() in knownPlayers:&lt;br /&gt;
            playerCount=playerCount+1       &lt;br /&gt;
    ctx.write(&#039;There are %i players from the list online.&#039;  % (playerCount) )&lt;br /&gt;
&lt;br /&gt;
def isOnList(player, ctx):&lt;br /&gt;
    global knownPlayers&lt;br /&gt;
    if player in knownPlayers:&lt;br /&gt;
        ctx.write(&#039;Player &#039; + player + &#039; is registered on the list.&#039;)&lt;br /&gt;
    else:&lt;br /&gt;
        ctx.write(&#039;Player &#039; + player + &#039; is *not* on the list.  Do what you must with him.&#039;)&lt;br /&gt;
&lt;br /&gt;
def removePlayerFromList(aPlayerName):&lt;br /&gt;
    global fileName, knownPlayers&lt;br /&gt;
    if not aPlayerName in knownPlayers:&lt;br /&gt;
        return&lt;br /&gt;
    knownPlayers.remove(aPlayerName)&lt;br /&gt;
    playersFile = file(fileName, &#039;w&#039;)&lt;br /&gt;
    playersFile.truncate(0)&lt;br /&gt;
    for aPlayer in knownPlayers:&lt;br /&gt;
        playersFile.write(aPlayer+&#039;\n&#039;)&lt;br /&gt;
    playersFile.close()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now overwrite the default.py file in your admin folder with this.&lt;br /&gt;
&lt;br /&gt;
default.py:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# vim: ts=4 noexpandtab&lt;br /&gt;
#&lt;br /&gt;
# Battlefield II -- default remote console module.&lt;br /&gt;
#&lt;br /&gt;
# This is a very simple, TCP based remote console which does simple MD5 digest&lt;br /&gt;
# password authentication. It can be configured via the admin/default.cfg file.&lt;br /&gt;
# Recognized options are &#039;port&#039; and &#039;password&#039;.&lt;br /&gt;
#&lt;br /&gt;
# Implementation guidelines for this file (and for your own rcon modules):&lt;br /&gt;
#&lt;br /&gt;
#  - All socket operations MUST be non-blocking. If your module blocks on a&lt;br /&gt;
#    socket the game server will hang.&lt;br /&gt;
#&lt;br /&gt;
#  - Do as little work as possible in update() as it runs in the server main&lt;br /&gt;
#    loop.&lt;br /&gt;
#&lt;br /&gt;
# Other notes:&lt;br /&gt;
#&lt;br /&gt;
#  - To get end-of-message markers (0x04 hex) after each reply, begin your&lt;br /&gt;
#    commands with an ascii 0x02 code. This module will then append the&lt;br /&gt;
#    end-of-message marker to all results. This is useful if you need to wait&lt;br /&gt;
#    for a complete response.&lt;br /&gt;
#&lt;br /&gt;
# Copyright (c)2004 Digital Illusions CE AB&lt;br /&gt;
# Author: Andreas `dep&#039; Fredriksson&lt;br /&gt;
&lt;br /&gt;
import socket&lt;br /&gt;
import errno&lt;br /&gt;
import host&lt;br /&gt;
import bf2&lt;br /&gt;
import types&lt;br /&gt;
import md5&lt;br /&gt;
import string&lt;br /&gt;
import random&lt;br /&gt;
import standard_admin.kickoutsiders&lt;br /&gt;
&lt;br /&gt;
options = {&lt;br /&gt;
    &#039;port&#039;: &#039;4711&#039;,&lt;br /&gt;
    &#039;password&#039;: None,&lt;br /&gt;
&lt;br /&gt;
    # True if multiple commands should be processed in one update and&lt;br /&gt;
    # if as many responses as possible should be sent each update.&lt;br /&gt;
    &#039;allowBatching&#039;: False&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
# Returns a seed string of random characters to be used as a salt to protect&lt;br /&gt;
# password sniffing.&lt;br /&gt;
def make_seed(seed_length):&lt;br /&gt;
    return &#039;&#039;.join([string.ascii_letters[random.randint(0, len(string.ascii_letters)-1)] for x in xrange(0, seed_length)])&lt;br /&gt;
&lt;br /&gt;
# Concats a seed string with the password and returns an ASCII-hex MD5 digest.&lt;br /&gt;
def digest(seed, pw):&lt;br /&gt;
    if not pw: return None&lt;br /&gt;
    m = md5.new()&lt;br /&gt;
    m.update(seed)&lt;br /&gt;
    m.update(pw)&lt;br /&gt;
    return m.hexdigest()&lt;br /&gt;
&lt;br /&gt;
# Parses the config file, if it&#039;s there&lt;br /&gt;
def parseConfig():&lt;br /&gt;
    def boolFromString (str):&lt;br /&gt;
        if str in [&#039;True&#039;, &#039;true&#039;, &#039;1&#039;]:&lt;br /&gt;
            return True&lt;br /&gt;
        elif value in [&#039;False&#039;, &#039;false&#039;, &#039;0&#039;]:&lt;br /&gt;
            return False&lt;br /&gt;
        else:&lt;br /&gt;
            raise ValueError&lt;br /&gt;
&lt;br /&gt;
    fn = &#039;admin/default.cfg&#039;&lt;br /&gt;
    try:&lt;br /&gt;
        config = open(fn, &#039;r&#039;)&lt;br /&gt;
        lineNo = 0&lt;br /&gt;
        for line in config:&lt;br /&gt;
            lineNo += 1&lt;br /&gt;
            if line.strip() != &#039;&#039; and line.strip() != &#039;\n&#039;:&lt;br /&gt;
                try:&lt;br /&gt;
                    (key, value) = line.split(&#039;=&#039;)&lt;br /&gt;
                    key = key.strip()&lt;br /&gt;
                    value = value.strip()&lt;br /&gt;
                   &lt;br /&gt;
                    if key == &#039;allowBatching&#039;: value = boolFromString (value)&lt;br /&gt;
                    options[key] = value&lt;br /&gt;
                   &lt;br /&gt;
                except ValueError:&lt;br /&gt;
                    print &#039;warning: syntax error in &amp;quot;%s&amp;quot; on line %d&#039; % (fn, lineNo)&lt;br /&gt;
    except IOError, detail:&lt;br /&gt;
        print &#039;warning: couldn\&#039;t read &amp;quot;%s&amp;quot;: %s&#039; % (fn, detail)&lt;br /&gt;
&lt;br /&gt;
# A stateful output buffer that knows how to enqueue data and ship it out&lt;br /&gt;
# without blocking.&lt;br /&gt;
class OutputBuffer(object):&lt;br /&gt;
&lt;br /&gt;
    def __init__(self, sock):&lt;br /&gt;
        self.sock = sock&lt;br /&gt;
        self.data = []&lt;br /&gt;
        self.index = 0&lt;br /&gt;
&lt;br /&gt;
    def enqueue(self, str):&lt;br /&gt;
        self.data.append(str)&lt;br /&gt;
&lt;br /&gt;
    def update(self):&lt;br /&gt;
        allowBatching = options[&#039;allowBatching&#039;]&lt;br /&gt;
        while len(self.data) &amp;gt; 0:&lt;br /&gt;
            try:&lt;br /&gt;
                item = self.data[0]&lt;br /&gt;
                scount = self.sock.send(item[self.index:])&lt;br /&gt;
                self.index += scount&lt;br /&gt;
                if self.index == len(item):&lt;br /&gt;
                    del self.data[0]&lt;br /&gt;
                    self.index = 0&lt;br /&gt;
            except socket.error, detail:&lt;br /&gt;
                if detail[0] != errno.EWOULDBLOCK:&lt;br /&gt;
                    return detail[1]&lt;br /&gt;
            if not allowBatching:&lt;br /&gt;
                break&lt;br /&gt;
        return None&lt;br /&gt;
&lt;br /&gt;
# Each TCP connection is represented by an object of this class.&lt;br /&gt;
class AdminConnection(object):&lt;br /&gt;
&lt;br /&gt;
    def __init__(self, srv, sock, addr):&lt;br /&gt;
        print &#039;new rcon/admin connection from %s:%d&#039; % (addr[0], addr[1])&lt;br /&gt;
        self.server = srv&lt;br /&gt;
        self.sock = sock&lt;br /&gt;
        self.addr = addr&lt;br /&gt;
        self.sock.setblocking(0)&lt;br /&gt;
        self.buffer = &#039;&#039;&lt;br /&gt;
        self.seed = make_seed(16)&lt;br /&gt;
        self.correct_digest = digest(self.seed, options[&#039;password&#039;])&lt;br /&gt;
        self.outbuf = OutputBuffer(self.sock)&lt;br /&gt;
       &lt;br /&gt;
        # Welcome message *must* end with \n\n&lt;br /&gt;
        self.outbuf.enqueue(&#039;### Battlefield 2 default RCON/admin ready.\n&#039;)&lt;br /&gt;
        self.outbuf.enqueue(&#039;### Digest seed: %s\n&#039; % (self.seed))&lt;br /&gt;
        self.outbuf.enqueue(&#039;\n&#039;) # terminate welcome message with extra LF&lt;br /&gt;
&lt;br /&gt;
    def update(self):&lt;br /&gt;
        err = None&lt;br /&gt;
        try:&lt;br /&gt;
            allowBatching = options[&#039;allowBatching&#039;]&lt;br /&gt;
            while not err:&lt;br /&gt;
                data = self.sock.recv(1024)&lt;br /&gt;
                if data:&lt;br /&gt;
                    self.buffer += data&lt;br /&gt;
                    while not err:&lt;br /&gt;
                        nlpos = self.buffer.find(&#039;\n&#039;)&lt;br /&gt;
                        if nlpos != -1:&lt;br /&gt;
                            self.server.onRemoteCommand(self, self.buffer[0:nlpos])&lt;br /&gt;
                            self.buffer = self.buffer[nlpos+1:] # keep rest of buffer&lt;br /&gt;
                        else:&lt;br /&gt;
                            if len(self.buffer) &amp;gt; 128:&lt;br /&gt;
                                err = &#039;data format error: no newline in message&#039;&lt;br /&gt;
                            break&lt;br /&gt;
                        if not allowBatching: break&lt;br /&gt;
                else:&lt;br /&gt;
                    err = &#039;peer disconnected&#039;&lt;br /&gt;
               &lt;br /&gt;
                if not allowBatching: break&lt;br /&gt;
&lt;br /&gt;
        except socket.error, detail:&lt;br /&gt;
            if detail[0] != errno.EWOULDBLOCK:&lt;br /&gt;
                err = detail[1]&lt;br /&gt;
&lt;br /&gt;
        if not err:&lt;br /&gt;
            err = self.outbuf.update()&lt;br /&gt;
&lt;br /&gt;
        if err:&lt;br /&gt;
            print &#039;rcon: closing %s:%d: %s&#039; % (self.addr[0], self.addr[1], err)&lt;br /&gt;
            try:&lt;br /&gt;
                self.sock.shutdown(2)&lt;br /&gt;
                self.sock.close()&lt;br /&gt;
            except:&lt;br /&gt;
                print &#039;rcon: warning: failed to close %s&#039; % (self.addr)&lt;br /&gt;
                pass&lt;br /&gt;
            return 0&lt;br /&gt;
        else:&lt;br /&gt;
            return 1&lt;br /&gt;
&lt;br /&gt;
# Context passed to remote command implementations for them to write output to&lt;br /&gt;
# either a remote tcp socket or an in-game client executing &#039;rcon &amp;lt;command&amp;gt;&#039;.&lt;br /&gt;
class CommandContext(object):&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        self.player = None&lt;br /&gt;
        self.socket = None&lt;br /&gt;
        self.output = []&lt;br /&gt;
&lt;br /&gt;
    def isInGame(self): return self.player is not None&lt;br /&gt;
    def isSocket(self): return self.socket is not None&lt;br /&gt;
    def write(self, text): self.output.append(text)&lt;br /&gt;
&lt;br /&gt;
# The server itself.&lt;br /&gt;
class AdminServer(object):&lt;br /&gt;
&lt;br /&gt;
    def __init__(self, port):&lt;br /&gt;
        # state for tcp rcon connections&lt;br /&gt;
        self.port = port&lt;br /&gt;
        self.backlog = 1&lt;br /&gt;
        self.peers = []&lt;br /&gt;
        self.openSocket()&lt;br /&gt;
&lt;br /&gt;
        # state for in-game rcon connections&lt;br /&gt;
        host.registerHandler(&#039;RemoteCommand&#039;, self.onRemoteCommand, 1)&lt;br /&gt;
        host.registerHandler(&#039;PlayerDisconnect&#039;, self.onPlayerDisconnect, 1)&lt;br /&gt;
        host.registerHandler(&#039;ChatMessage&#039;, self.onChatMessage, 1)&lt;br /&gt;
&lt;br /&gt;
        # contains player ids for players which have successfully authenticated&lt;br /&gt;
        # themselves with &#039;rcon login &amp;lt;passwd&amp;gt;&#039;&lt;br /&gt;
        self.authed_players = {}&lt;br /&gt;
        # contains sockets for connections which have successfully authenticated&lt;br /&gt;
        # themselves with &#039;login &amp;lt;passwd&amp;gt;&#039;&lt;br /&gt;
        self.authed_sockets = {}&lt;br /&gt;
&lt;br /&gt;
        # rcon commands supported in this vanilla version&lt;br /&gt;
        self.rcon_cmds = {&lt;br /&gt;
            &#039;login&#039;: self.rcmd_login,&lt;br /&gt;
            &#039;users&#039;: self.rcmd_users,&lt;br /&gt;
            &#039;exec&#039;: self.rcmd_exec,&lt;br /&gt;
            &#039;addPlayer&#039;: self.rcmd_addPlayer,&lt;br /&gt;
            &#039;removePlayer&#039;: self.rcmd_removePlayer,&lt;br /&gt;
            &#039;changeMode&#039;: self.rcmd_changeMode,&lt;br /&gt;
            &#039;currentMode&#039;: self.rcmd_currMode,&lt;br /&gt;
            &#039;numFromList&#039;: self.rcmd_numFromList,&lt;br /&gt;
            &#039;isOnList&#039;: self.rcmd_isOnList&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
    # Called when a user types &#039;rcon &#039; followed by any string in a client&lt;br /&gt;
    # console window or when a TCP client sends a complete line to be&lt;br /&gt;
    # evaluated.&lt;br /&gt;
    def onRemoteCommand(self, playerid_or_socket, cmd):&lt;br /&gt;
        cmd = cmd.strip()&lt;br /&gt;
        interactive = True&lt;br /&gt;
&lt;br /&gt;
        # Is this a non-interactive client?&lt;br /&gt;
        if len(cmd) &amp;gt; 0 and cmd[0] == &#039;\x02&#039;:&lt;br /&gt;
            cmd = cmd[1:]&lt;br /&gt;
            interactive = False&lt;br /&gt;
&lt;br /&gt;
        spacepos = cmd.find(&#039; &#039;)&lt;br /&gt;
        if spacepos == -1: spacepos=len(cmd)&lt;br /&gt;
        subcmd = cmd[0:spacepos]&lt;br /&gt;
&lt;br /&gt;
        ctx = CommandContext()&lt;br /&gt;
        authed = 0&lt;br /&gt;
        if type(playerid_or_socket) == types.IntType:&lt;br /&gt;
            ctx.player = playerid_or_socket&lt;br /&gt;
            authed = self.authed_players.has_key(ctx.player)&lt;br /&gt;
        else:&lt;br /&gt;
            ctx.socket = playerid_or_socket&lt;br /&gt;
            authed = self.authed_sockets.has_key(ctx.socket)&lt;br /&gt;
           &lt;br /&gt;
        # you can only login unless you are authenticated&lt;br /&gt;
        if subcmd != &#039;login&#039; and not authed:&lt;br /&gt;
            ctx.write(&#039;error: not authenticated: you can only invoke \&#039;login\&#039;\n&#039;)&lt;br /&gt;
        else:&lt;br /&gt;
            if self.rcon_cmds.has_key(subcmd):&lt;br /&gt;
                self.rcon_cmds[subcmd](ctx, cmd[spacepos+1:])&lt;br /&gt;
            else:&lt;br /&gt;
                ctx.write(&#039;unknown command: \&#039;%s\&#039;\n&#039; % (subcmd))&lt;br /&gt;
&lt;br /&gt;
        feedback = &#039;&#039;.join(ctx.output)&lt;br /&gt;
        if ctx.socket:&lt;br /&gt;
            if interactive:&lt;br /&gt;
                ctx.socket.outbuf.enqueue(feedback)&lt;br /&gt;
            else:&lt;br /&gt;
                ctx.socket.outbuf.enqueue(feedback + &#039;\x04&#039;)&lt;br /&gt;
        else:&lt;br /&gt;
            host.rcon_feedback(ctx.player, feedback)&lt;br /&gt;
&lt;br /&gt;
    # When players disconnect, remove them from the auth map if they were&lt;br /&gt;
    # authenticated so that the next user with the same id doesn&#039;t get rcon&lt;br /&gt;
    # access.&lt;br /&gt;
    def onPlayerDisconnect(self, player_id):&lt;br /&gt;
        if self.authed_players.has_key(player_id):&lt;br /&gt;
            del self.authed_players[player_id]&lt;br /&gt;
&lt;br /&gt;
    # Called whenever a player issues a chat string.&lt;br /&gt;
    def onChatMessage(self, player_id, text, channel, flags):&lt;br /&gt;
        print &#039;chat: pid=%d text=\&#039;%s\&#039; channel=%s&#039; % (player_id, text, channel)&lt;br /&gt;
&lt;br /&gt;
    # Sets up the listening TCP RCON socket. This binds to 0.0.0.0, which may&lt;br /&gt;
    # not be what you want but it&#039;s a sane default for most installations.&lt;br /&gt;
    def openSocket(self):&lt;br /&gt;
        try:&lt;br /&gt;
            self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)&lt;br /&gt;
            #self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, 0)&lt;br /&gt;
            #self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)&lt;br /&gt;
            self.sock.bind((&#039;0.0.0.0&#039;, self.port))&lt;br /&gt;
            self.sock.listen(self.backlog)&lt;br /&gt;
            self.sock.setblocking(0)&lt;br /&gt;
        except socket.error, detail:&lt;br /&gt;
            print &#039;failed to bind rcon socket--only in-game rcon will be enabled&#039;&lt;br /&gt;
&lt;br /&gt;
    # WARNING: update is called very frequently -- don&#039;t go crazy with logic&lt;br /&gt;
    # here.&lt;br /&gt;
    def update(self):&lt;br /&gt;
        # if we don&#039;t have a socket, just return&lt;br /&gt;
        if not self.sock: return&lt;br /&gt;
&lt;br /&gt;
        # without blocking, check for new connections&lt;br /&gt;
        try:&lt;br /&gt;
            conn, peeraddr = self.sock.accept()&lt;br /&gt;
            self.peers.append(AdminConnection(self, conn, peeraddr))&lt;br /&gt;
        except socket.error, detail:&lt;br /&gt;
            if detail[0] != errno.EWOULDBLOCK:&lt;br /&gt;
                raise socket.error, detail&lt;br /&gt;
&lt;br /&gt;
        # update clients and mark connections that fail their update&lt;br /&gt;
        disc = []&lt;br /&gt;
        for client in self.peers:&lt;br /&gt;
            if not client.update(): disc.append(client)&lt;br /&gt;
&lt;br /&gt;
        # delete any auth status for closed tcp connections&lt;br /&gt;
        for d in disc:&lt;br /&gt;
            if self.authed_sockets.has_key(d): del self.authed_sockets[d]&lt;br /&gt;
&lt;br /&gt;
        # now keep the remaining clients&lt;br /&gt;
        self.peers = filter(lambda x: x not in disc, self.peers)&lt;br /&gt;
&lt;br /&gt;
    def shutdown(self):&lt;br /&gt;
        if self.sock:&lt;br /&gt;
            self.sock.close()&lt;br /&gt;
&lt;br /&gt;
    # Command implementations go here (member functions of the AdminServer)&lt;br /&gt;
&lt;br /&gt;
    # Allows a in-game rcon client to authenticate and get access.&lt;br /&gt;
    def rcmd_login(self, ctx, cmd):&lt;br /&gt;
        success = 0&lt;br /&gt;
        if ctx.isInGame():&lt;br /&gt;
            # We&#039;re called by an in-game rcon client, use plain-text password&lt;br /&gt;
            # (encoded into bf2 network stream).&lt;br /&gt;
            if cmd.strip() == options[&#039;password&#039;]:&lt;br /&gt;
                    self.authed_players[ctx.player] = 1&lt;br /&gt;
                    success = 1&lt;br /&gt;
            elif self.authed_players.has_key(ctx.player):&lt;br /&gt;
                    del self.authed_players[ctx.player]&lt;br /&gt;
        else:&lt;br /&gt;
            # tcp client, require seeded digest to match instead of pw&lt;br /&gt;
            if cmd.strip() == ctx.socket.correct_digest:&lt;br /&gt;
                self.authed_sockets[ctx.socket] = 1&lt;br /&gt;
                print &#039;rcon: tcp client from %s:%d logged on&#039; % ctx.socket.addr&lt;br /&gt;
                success = 1&lt;br /&gt;
            else:&lt;br /&gt;
                if self.authed_sockets.has_key(ctx.socket):&lt;br /&gt;
                    del self.authed_sockets[ctx.socket]&lt;br /&gt;
                print &#039;rcon: tcp client from %s:%d failed pw challenge&#039; % ctx.socket.addr&lt;br /&gt;
&lt;br /&gt;
        if success:&lt;br /&gt;
            ctx.write(&#039;Authentication successful, rcon ready.\n&#039;)&lt;br /&gt;
        else:&lt;br /&gt;
            ctx.write(&#039;Authentication failed.\n&#039;)&lt;br /&gt;
&lt;br /&gt;
    # Lists rcon-authenticated players.&lt;br /&gt;
    def rcmd_users(self, ctx, cmd):&lt;br /&gt;
        ctx.write(&#039;active rcon users:\n&#039;)&lt;br /&gt;
        for id in self.authed_players:&lt;br /&gt;
            if id == -1:&lt;br /&gt;
                ctx.write(&#039;-1 (local server console)\n&#039;)&lt;br /&gt;
            else:&lt;br /&gt;
                try:&lt;br /&gt;
                    player = bf2.playerManager.getPlayerByIndex(id)&lt;br /&gt;
                    ctx.write(&#039;%d from %s name=\&#039;%s\&#039;\n&#039; % (id, player.getAddress(), player.getName()))&lt;br /&gt;
                except:&lt;br /&gt;
                    ctx.write(&#039;%d (no info)\n&#039; % (id))&lt;br /&gt;
&lt;br /&gt;
        for peer in self.authed_sockets:&lt;br /&gt;
            ctx.write(&#039;tcp: %s:%d\n&#039; % (peer.addr[0], peer.addr[1]))&lt;br /&gt;
&lt;br /&gt;
    # Executes a console command on the server.&lt;br /&gt;
    def rcmd_exec(self, ctx, cmd):&lt;br /&gt;
        ctx.write(host.rcon_invoke(cmd))&lt;br /&gt;
       &lt;br /&gt;
    def rcmd_addPlayer(self, ctx, cmd):&lt;br /&gt;
        ctx.write(&#039;Adding player &#039; + cmd)&lt;br /&gt;
        standard_admin.kickoutsiders.addPlayerToList(cmd)&lt;br /&gt;
       &lt;br /&gt;
    def rcmd_removePlayer(self, ctx, cmd):&lt;br /&gt;
        ctx.write(&#039;Removing player &#039; + cmd)&lt;br /&gt;
        standard_admin.kickoutsiders.removePlayerFromList(cmd)&lt;br /&gt;
       &lt;br /&gt;
    def rcmd_changeMode(self, ctx, cmd):&lt;br /&gt;
        standard_admin.kickoutsiders.changeMode(cmd)&lt;br /&gt;
       &lt;br /&gt;
    def rcmd_currMode(self, ctx, cmd):&lt;br /&gt;
        standard_admin.kickoutsiders.writeMode(ctx)&lt;br /&gt;
       &lt;br /&gt;
    def rcmd_numFromList(self, ctx, cmd):&lt;br /&gt;
        standard_admin.kickoutsiders.writeNumList(ctx)&lt;br /&gt;
       &lt;br /&gt;
    def rcmd_isOnList(self, ctx, cmd):&lt;br /&gt;
        standard_admin.kickoutsiders.isOnList(cmd, ctx)&lt;br /&gt;
&lt;br /&gt;
# parse the configuration file&lt;br /&gt;
parseConfig()&lt;br /&gt;
&lt;br /&gt;
# our single server instance&lt;br /&gt;
server = AdminServer(int(options[&#039;port&#039;]))&lt;br /&gt;
&lt;br /&gt;
# These functions are called from the engine -- we implement them in terms of a&lt;br /&gt;
# class instance:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def init():&lt;br /&gt;
    print &#039;initializing default admin/rcon module&#039;&lt;br /&gt;
   &lt;br /&gt;
    # load (optional) admin scripts like teamkill punish and autobalance&lt;br /&gt;
    import standard_admin&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def shutdown():&lt;br /&gt;
    if server:&lt;br /&gt;
        print &#039;shutting down default admin/rcon module&#039;&lt;br /&gt;
        server.shutdown()&lt;br /&gt;
&lt;br /&gt;
def update():&lt;br /&gt;
    if server: server.update()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
note from Milton: Wow this script seems to be really good, unfortunately I cannot test it because I am using BF2CC, do you think that you could modify the default.py that BF2CC has in order to make it so that we can use both BF2CC and your script?&lt;br /&gt;
&lt;br /&gt;
note from Brian:I&#039;ve adapted the script for the BF2CC app. Enjoy!&lt;br /&gt;
&lt;br /&gt;
default.py&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# vim: ts=4 noexpandtab&lt;br /&gt;
#&lt;br /&gt;
# Battlefield II -- default remote console module.&lt;br /&gt;
#&lt;br /&gt;
# This is a very simple, TCP based remote console which does simple MD5 digest&lt;br /&gt;
# password authentication. It can be configured via the admin/default.cfg file.&lt;br /&gt;
# Recognized options are &#039;port&#039; and &#039;password&#039;.&lt;br /&gt;
#&lt;br /&gt;
# Implementation guidelines for this file (and for your own rcon modules):&lt;br /&gt;
#&lt;br /&gt;
#  - All socket operations MUST be non-blocking. If your module blocks on a&lt;br /&gt;
#    socket the game server will hang.&lt;br /&gt;
#&lt;br /&gt;
#  - Do as little work as possible in update() as it runs in the server main&lt;br /&gt;
#    loop.&lt;br /&gt;
#&lt;br /&gt;
# Other notes:&lt;br /&gt;
#&lt;br /&gt;
#  - To get end-of-message markers (0x04 hex) after each reply, begin your&lt;br /&gt;
#    commands with an ascii 0x02 code. This module will then append the&lt;br /&gt;
#    end-of-message marker to all results. This is useful if you need to wait&lt;br /&gt;
#    for a complete response.&lt;br /&gt;
#&lt;br /&gt;
# Copyright (c)2004 Digital Illusions CE AB&lt;br /&gt;
# Author: Andreas `dep&#039; Fredriksson&lt;br /&gt;
#&lt;br /&gt;
# This version of this script is managed by the BF2CC crew.&lt;br /&gt;
#&lt;br /&gt;
# CHANGE LOG&lt;br /&gt;
# June 13 - Hooked in BF2CC.py file.  Seperating BF2CC custom commands from EA&#039;s customs commands.&lt;br /&gt;
#&lt;br /&gt;
# June 25 - Added exception handlers for all functions.&lt;br /&gt;
# June 25 - Added python log file support for errors and &#039;print&#039; statements in the python code. (redir of stdout) options - pythonlogfile&lt;br /&gt;
# June 25 - Added support for alternative IP binding.  options - ip&lt;br /&gt;
#&lt;br /&gt;
# Version 3.5&lt;br /&gt;
# July 5 - Added some security related fixes&lt;br /&gt;
# July 5 - Added player rank into player list function&lt;br /&gt;
&lt;br /&gt;
import socket&lt;br /&gt;
import errno&lt;br /&gt;
import host&lt;br /&gt;
import bf2&lt;br /&gt;
import types&lt;br /&gt;
import md5&lt;br /&gt;
import string&lt;br /&gt;
import random&lt;br /&gt;
import bf2cc # Added BF2CC June 13, 2005&lt;br /&gt;
import sys&lt;br /&gt;
import standard_admin.kickoutsiders&lt;br /&gt;
&lt;br /&gt;
# Set these options in the default.cfg&lt;br /&gt;
options = {&lt;br /&gt;
    &#039;port&#039;: &#039;4711&#039;,&lt;br /&gt;
    &#039;password&#039;: None,&lt;br /&gt;
        &#039;ip&#039;: &#039;0.0.0.0&#039;, # Added BF2CC rbarone&lt;br /&gt;
        &#039;pythonlogfile&#039;: &#039;pythonlog.txt&#039; # Added BF2CC rbarone&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
# Function added BF2CC rbarone&lt;br /&gt;
def printExceptionTrace(e, location):&lt;br /&gt;
        # generate line number&lt;br /&gt;
        lineNum = &#039;&#039;&lt;br /&gt;
        execInfo = sys.exc_info()&lt;br /&gt;
        tb = execInfo[2]&lt;br /&gt;
        while tb is not None:&lt;br /&gt;
                if lineNum == &#039;&#039;:&lt;br /&gt;
                        lineNum = str(tb.tb_lineno)&lt;br /&gt;
                else:&lt;br /&gt;
                        lineNum += &#039;, &#039; + str(tb.tb_lineno)&lt;br /&gt;
                tb = tb.tb_next&lt;br /&gt;
       &lt;br /&gt;
        print(&#039;**** ERROR ERROR ERROR ****\n  Exception generated in %s\n     %s\n     %s\n     (Line(s): %s)\n&#039; % (location, str(execInfo[0]), str(e), lineNum))&lt;br /&gt;
        if options[&#039;pythonlogfile&#039;] != &#039;&#039;:&lt;br /&gt;
                sys.stdout.flush()&lt;br /&gt;
&lt;br /&gt;
# Returns a seed string of random characters to be used as a salt to protect&lt;br /&gt;
# password sniffing.&lt;br /&gt;
def make_seed(seed_length):&lt;br /&gt;
    return &#039;&#039;.join([string.ascii_letters[random.randint(0, len(string.ascii_letters)-1)] for x in xrange(0, seed_length)])&lt;br /&gt;
&lt;br /&gt;
# Concats a seed string with the password and returns an ASCII-hex MD5 digest.&lt;br /&gt;
def digest(seed, pw):&lt;br /&gt;
    if not pw: return None&lt;br /&gt;
    m = md5.new()&lt;br /&gt;
    m.update(seed)&lt;br /&gt;
    m.update(pw)&lt;br /&gt;
    return m.hexdigest()&lt;br /&gt;
&lt;br /&gt;
# Parses the config file, if it&#039;s there&lt;br /&gt;
def parseConfig():&lt;br /&gt;
    def boolFromString (str):&lt;br /&gt;
        if str in [&#039;True&#039;, &#039;true&#039;, &#039;1&#039;]:&lt;br /&gt;
            return True&lt;br /&gt;
        elif value in [&#039;False&#039;, &#039;false&#039;, &#039;0&#039;]:&lt;br /&gt;
            return False&lt;br /&gt;
        else:&lt;br /&gt;
            raise ValueError&lt;br /&gt;
&lt;br /&gt;
    fn = &#039;admin/default.cfg&#039;&lt;br /&gt;
    try:&lt;br /&gt;
        config = open(fn, &#039;r&#039;)&lt;br /&gt;
        lineNo = 0&lt;br /&gt;
        for line in config:&lt;br /&gt;
            lineNo += 1&lt;br /&gt;
            if line.strip() != &#039;&#039; and line.strip() != &#039;\n&#039;:&lt;br /&gt;
                try:&lt;br /&gt;
                    (key, value) = line.split(&#039;=&#039;)&lt;br /&gt;
                    key = key.strip()&lt;br /&gt;
                    value = value.strip()&lt;br /&gt;
                   &lt;br /&gt;
                    #if key == &#039;allowBatching&#039;: value = boolFromString (value) # Removed BF2CC rbarone&lt;br /&gt;
                    options[key] = value&lt;br /&gt;
                   &lt;br /&gt;
                except ValueError:&lt;br /&gt;
                    print &#039;warning: syntax error in &amp;quot;%s&amp;quot; on line %d&#039; % (fn, lineNo)&lt;br /&gt;
    except IOError, detail:&lt;br /&gt;
        print &#039;warning: couldn\&#039;t read &amp;quot;%s&amp;quot;: %s&#039; % (fn, detail)&lt;br /&gt;
        except Exception, e:&lt;br /&gt;
                printExceptionTrace(e, &#039;parseConfig&#039;)&lt;br /&gt;
               &lt;br /&gt;
        if options[&#039;pythonlogfile&#039;] != &#039;&#039;:&lt;br /&gt;
                global stdoutFlushTimer&lt;br /&gt;
               &lt;br /&gt;
                stdoutFlushTimer = bf2.Timer(onFlushStdout, 10, 1)&lt;br /&gt;
                stdoutFlushTimer.setRecurring(10)&lt;br /&gt;
&lt;br /&gt;
                sys.stdout = file(options[&#039;pythonlogfile&#039;], &#039;a&#039;)&lt;br /&gt;
&lt;br /&gt;
def onFlushStdout(data):&lt;br /&gt;
        try:&lt;br /&gt;
                sys.stdout.flush()&lt;br /&gt;
        except:&lt;br /&gt;
                print &#039;could not flush&#039;&lt;br /&gt;
                pass&lt;br /&gt;
               &lt;br /&gt;
# A stateful output buffer that knows how to enqueue data and ship it out&lt;br /&gt;
# without blocking.&lt;br /&gt;
class OutputBuffer(object):&lt;br /&gt;
    def __init__(self, sock):&lt;br /&gt;
        self.sock = sock&lt;br /&gt;
        self.data = []&lt;br /&gt;
        self.index = 0&lt;br /&gt;
&lt;br /&gt;
    def enqueue(self, str):&lt;br /&gt;
        try:                    # Added BF2CC rbaron&lt;br /&gt;
                        self.data.append(str)&lt;br /&gt;
                except Exception, e:&lt;br /&gt;
                        printExceptionTrace(e, &#039;enqueue&#039;)&lt;br /&gt;
&lt;br /&gt;
    def update(self):&lt;br /&gt;
        allowBatching = True # Changed BF2CC rbarone - Always set to true&lt;br /&gt;
        while len(self.data) &amp;gt; 0:&lt;br /&gt;
            try:&lt;br /&gt;
                item = self.data[0]&lt;br /&gt;
                scount = self.sock.send(item[self.index:])&lt;br /&gt;
                self.index += scount&lt;br /&gt;
                if self.index == len(item):&lt;br /&gt;
                    del self.data[0]&lt;br /&gt;
                    self.index = 0&lt;br /&gt;
            except socket.error, detail:&lt;br /&gt;
                if detail[0] != errno.EWOULDBLOCK:&lt;br /&gt;
                    return detail[1]&lt;br /&gt;
                        except Exception, e:&lt;br /&gt;
                                printExceptionTrace(e, &#039;OutputBuffer.update&#039;)&lt;br /&gt;
                       &lt;br /&gt;
                        # if not allowBatching: # Removed BF2CC rbarone&lt;br /&gt;
            #    break&lt;br /&gt;
        return None&lt;br /&gt;
&lt;br /&gt;
# Each TCP connection is represented by an object of this class.&lt;br /&gt;
class AdminConnection(object):&lt;br /&gt;
&lt;br /&gt;
    def __init__(self, srv, sock, addr):&lt;br /&gt;
        try:               &lt;br /&gt;
                        print &#039;new rcon/admin connection from %s:%d&#039; % (addr[0], addr[1])&lt;br /&gt;
                        self.server = srv&lt;br /&gt;
                        self.sock = sock&lt;br /&gt;
                        self.addr = addr&lt;br /&gt;
                        self.sock.setblocking(0)&lt;br /&gt;
                        self.buffer = &#039;&#039;&lt;br /&gt;
                        self.seed = make_seed(16)&lt;br /&gt;
                        self.correct_digest = digest(self.seed, options[&#039;password&#039;])&lt;br /&gt;
                        self.outbuf = OutputBuffer(self.sock)&lt;br /&gt;
                                       &lt;br /&gt;
                        self.bf2ccClient = bf2cc.Client(srv.bf2ccServer) # Added BF2CC June 13, 2005 rbarone&lt;br /&gt;
       &lt;br /&gt;
                        # Welcome message *must* end with \n\n&lt;br /&gt;
                        self.outbuf.enqueue(&#039;### Battlefield 2 version &#039; + bf2cc.scriptVersion + &#039; &#039; + bf2cc.serverType + &#039; default RCON/admin ready.\n&#039;) # Changed BF2CC - Added script version rbarone&lt;br /&gt;
                        self.outbuf.enqueue(&#039;### Digest seed: %s\n&#039; % (self.seed))&lt;br /&gt;
                        self.outbuf.enqueue(&#039;\n&#039;) # terminate welcome message with extra LF&lt;br /&gt;
                except Exception, e:&lt;br /&gt;
                        printExceptionTrace(e, &#039;AdminConnection.__init__&#039;)&lt;br /&gt;
                       &lt;br /&gt;
    def update(self):&lt;br /&gt;
        err = None&lt;br /&gt;
        try:&lt;br /&gt;
            allowBatching = True # Changed BF2CC - Always set to true&lt;br /&gt;
            while not err:&lt;br /&gt;
                                data = self.sock.recv(1024)&lt;br /&gt;
                                if data:&lt;br /&gt;
                                        self.buffer += data&lt;br /&gt;
                                        while not err:&lt;br /&gt;
                                                nlpos = self.buffer.find(&#039;\n&#039;)&lt;br /&gt;
                                                if nlpos != -1:&lt;br /&gt;
                                                        self.server.onRemoteCommand(self, self.buffer[0:nlpos])&lt;br /&gt;
                                                        self.buffer = self.buffer[nlpos+1:] # keep rest of buffer&lt;br /&gt;
                                                else:&lt;br /&gt;
                                                        if len(self.buffer) &amp;gt; 128:&lt;br /&gt;
                                                                err = &#039;data format error: no newline in message&#039;&lt;br /&gt;
                                                        break&lt;br /&gt;
                                                #if not allowBatching: break # Removed BF2CC rbarone&lt;br /&gt;
                                else:&lt;br /&gt;
                                        err = &#039;peer disconnected&#039;&lt;br /&gt;
                                       &lt;br /&gt;
                #if not allowBatching: break #Removed BF2CC rbarone&lt;br /&gt;
&lt;br /&gt;
        except socket.error, detail:&lt;br /&gt;
            if detail[0] != errno.EWOULDBLOCK:&lt;br /&gt;
                err = detail[1]&lt;br /&gt;
                except Exception, e:&lt;br /&gt;
                        printExceptionTrace(e, &#039;AdminConnection.update&#039;)&lt;br /&gt;
                        err = &#039;Exception in AdminConnection.update&#039;&lt;br /&gt;
&lt;br /&gt;
                try:&lt;br /&gt;
&lt;br /&gt;
                        if not err:&lt;br /&gt;
                                err = self.outbuf.update()&lt;br /&gt;
       &lt;br /&gt;
                        if err:&lt;br /&gt;
                                print &#039;rcon: closing %s:%d: %s&#039; % (self.addr[0], self.addr[1], err)&lt;br /&gt;
                                self.bf2ccClient.UnregisterClient() # Added BF2CC June 13, 2005 rbarone&lt;br /&gt;
                                try:&lt;br /&gt;
                                        self.bf2ccClient = None&lt;br /&gt;
                                        self.sock.shutdown(2)&lt;br /&gt;
                                        self.sock.close()&lt;br /&gt;
                                except:&lt;br /&gt;
                                        print &#039;rcon: warning: failed to close %s&#039; % (self.addr)&lt;br /&gt;
                                        pass&lt;br /&gt;
                                return 0&lt;br /&gt;
                        else:&lt;br /&gt;
                                return 1&lt;br /&gt;
                except Exception, e:&lt;br /&gt;
                        printExceptionTrace(e, &#039;AdminConnection.update&#039;)&lt;br /&gt;
                        err = &#039;Exception in AdminConnection.update&#039;&lt;br /&gt;
&lt;br /&gt;
# Context passed to remote command implementations for them to write output to&lt;br /&gt;
# either a remote tcp socket or an in-game client executing &#039;rcon &amp;lt;command&amp;gt;&#039;.&lt;br /&gt;
class CommandContext(object):&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        self.player = None&lt;br /&gt;
        self.socket = None&lt;br /&gt;
        self.output = []&lt;br /&gt;
&lt;br /&gt;
    def isInGame(self): return self.player is not None&lt;br /&gt;
    def isSocket(self): return self.socket is not None&lt;br /&gt;
    def write(self, text): self.output.append(text)&lt;br /&gt;
&lt;br /&gt;
# The server itself.&lt;br /&gt;
class AdminServer(object):&lt;br /&gt;
&lt;br /&gt;
    def __init__(self, port):&lt;br /&gt;
        try:               &lt;br /&gt;
                        # state for tcp rcon connections&lt;br /&gt;
                        self.port = port&lt;br /&gt;
                        self.backlog = 1&lt;br /&gt;
                        self.peers = []&lt;br /&gt;
                        self.openSocket()&lt;br /&gt;
       &lt;br /&gt;
                        # state for in-game rcon connections&lt;br /&gt;
                        host.registerHandler(&#039;RemoteCommand&#039;, self.onRemoteCommand, 1)&lt;br /&gt;
                        host.registerHandler(&#039;PlayerDisconnect&#039;, self.onPlayerDisconnect, 1)&lt;br /&gt;
                        host.registerHandler(&#039;ChatMessage&#039;, self.onChatMessage, 1)&lt;br /&gt;
       &lt;br /&gt;
                        # contains player ids for players which have successfully authenticated&lt;br /&gt;
                        # themselves with &#039;rcon login &amp;lt;passwd&amp;gt;&#039;&lt;br /&gt;
                        self.authed_players = {}&lt;br /&gt;
                        # contains sockets for connections which have successfully authenticated&lt;br /&gt;
                        # themselves with &#039;login &amp;lt;passwd&amp;gt;&#039;&lt;br /&gt;
                        self.authed_sockets = {}&lt;br /&gt;
       &lt;br /&gt;
                        # rcon commands supported in this vanilla version&lt;br /&gt;
                        self.rcon_cmds = {&lt;br /&gt;
                                &#039;login&#039;: self.rcmd_login,&lt;br /&gt;
                                &#039;users&#039;: self.rcmd_users,&lt;br /&gt;
                                &#039;exec&#039;: self.rcmd_exec,&lt;br /&gt;
                                &#039;bf2cc&#039;: self.rcmd_bf2cc,&lt;br /&gt;
                                &#039;addPlayer&#039;: self.rcmd_addPlayer,&lt;br /&gt;
                                &#039;removePlayer&#039;: self.rcmd_removePlayer,&lt;br /&gt;
                                &#039;changeMode&#039;: self.rcmd_changeMode,&lt;br /&gt;
                                &#039;currMode&#039;: self.rcmd_currMode,&lt;br /&gt;
                                &#039;numFromList&#039;: self.rcmd_numFromList,&lt;br /&gt;
                                &#039;isOnList&#039;: self.rcmd_isOnList,&lt;br /&gt;
                        }&lt;br /&gt;
                       &lt;br /&gt;
                        self.bf2ccServer = bf2cc.Server(self) # Added BF2CC June 13, 2005&lt;br /&gt;
                        #self.bf2ccServer.RegisterServer(self) # Added BF2CC June 13, 2005&lt;br /&gt;
                except Exception, e:&lt;br /&gt;
                        printExceptionTrace(e, &#039;AdminServer.__init__&#039;)&lt;br /&gt;
                        raise e&lt;br /&gt;
&lt;br /&gt;
    # Called when a user types &#039;rcon &#039; followed by any string in a client&lt;br /&gt;
    # console window or when a TCP client sends a complete line to be&lt;br /&gt;
    # evaluated.&lt;br /&gt;
    def onRemoteCommand(self, playerid_or_socket, cmd):&lt;br /&gt;
        try:&lt;br /&gt;
                        cmd = cmd.strip()&lt;br /&gt;
                        interactive = True&lt;br /&gt;
       &lt;br /&gt;
                        # Is this a non-interactive client?&lt;br /&gt;
                        if len(cmd) &amp;gt; 0 and cmd[0] == &#039;\x02&#039;:&lt;br /&gt;
                                cmd = cmd[1:]&lt;br /&gt;
                                interactive = False&lt;br /&gt;
       &lt;br /&gt;
                        spacepos = cmd.find(&#039; &#039;)&lt;br /&gt;
                        if spacepos == -1: spacepos=len(cmd)&lt;br /&gt;
                        subcmd = cmd[0:spacepos]&lt;br /&gt;
       &lt;br /&gt;
                        ctx = CommandContext()&lt;br /&gt;
                        authed = 0&lt;br /&gt;
                        if type(playerid_or_socket) == types.IntType:&lt;br /&gt;
                                ctx.player = playerid_or_socket&lt;br /&gt;
                                authed = self.authed_players.has_key(ctx.player)&lt;br /&gt;
                        else:&lt;br /&gt;
                                ctx.socket = playerid_or_socket&lt;br /&gt;
                                authed = self.authed_sockets.has_key(ctx.socket)&lt;br /&gt;
                               &lt;br /&gt;
                        # you can only login unless you are authenticated&lt;br /&gt;
                        if subcmd != &#039;login&#039; and not authed:&lt;br /&gt;
                                ctx.write(&#039;error: not authenticated: you can only invoke \&#039;login\&#039;\n&#039;)&lt;br /&gt;
                        else:&lt;br /&gt;
                                if self.rcon_cmds.has_key(subcmd):&lt;br /&gt;
                                        self.rcon_cmds[subcmd](ctx, cmd[spacepos+1:])&lt;br /&gt;
                                else:&lt;br /&gt;
                                        ctx.write(&#039;unknown command: \&#039;%s\&#039;\n&#039; % (subcmd))&lt;br /&gt;
       &lt;br /&gt;
                        feedback = &#039;&#039;.join(ctx.output)&lt;br /&gt;
                        if ctx.socket:&lt;br /&gt;
                                if interactive:&lt;br /&gt;
                                        ctx.socket.outbuf.enqueue(feedback)&lt;br /&gt;
                                else:&lt;br /&gt;
                                        ctx.socket.outbuf.enqueue(feedback + &#039;\x04&#039;)&lt;br /&gt;
                        else:&lt;br /&gt;
                                host.rcon_feedback(ctx.player, feedback)&lt;br /&gt;
                except Exception, e:&lt;br /&gt;
                        printExceptionTrace(e, &#039;AdminServer.onRemoteCommand&#039;)&lt;br /&gt;
&lt;br /&gt;
    # When players disconnect, remove them from the auth map if they were&lt;br /&gt;
    # authenticated so that the next user with the same id doesn&#039;t get rcon&lt;br /&gt;
    # access.&lt;br /&gt;
    def onPlayerDisconnect(self, player):&lt;br /&gt;
        try:&lt;br /&gt;
                        if self.authed_players.has_key(player.index):&lt;br /&gt;
                                print(&#039;Removing PlayerID: %s&#039; % str(player.index))&lt;br /&gt;
                                del self.authed_players[player.index]&lt;br /&gt;
                except Exception, e:&lt;br /&gt;
                        printExceptionTrace(e, &#039;AdminServer.onPlayerDisconnect&#039;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    # Called whenever a player issues a chat string.&lt;br /&gt;
    def onChatMessage(self, player_id, text, channel, flags):&lt;br /&gt;
        try:&lt;br /&gt;
                        print &#039;chat: pid=%d text=\&#039;%s\&#039; channel=%s&#039; % (player_id, text, channel)&lt;br /&gt;
                except Exception, e:&lt;br /&gt;
                        printExceptionTrace(e, &#039;AdminServer.onChatMessage&#039;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    # Sets up the listening TCP RCON socket. This binds to 0.0.0.0, which may&lt;br /&gt;
    # not be what you want but it&#039;s a sane default for most installations.&lt;br /&gt;
    def openSocket(self):&lt;br /&gt;
        try:&lt;br /&gt;
            self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)&lt;br /&gt;
            #self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, 0)&lt;br /&gt;
            #self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)&lt;br /&gt;
            self.sock.bind((options[&#039;ip&#039;], self.port))&lt;br /&gt;
            self.sock.listen(self.backlog)&lt;br /&gt;
            self.sock.setblocking(0)&lt;br /&gt;
        except socket.error, detail:&lt;br /&gt;
            print &#039;failed to bind rcon socket.  Check the IP and port configured, it may be in use by another program.&#039;&lt;br /&gt;
                        self.sock = None&lt;br /&gt;
                except Exception, e:&lt;br /&gt;
                        printExceptionTrace(e, &#039;AdminServer.openSocket&#039;)&lt;br /&gt;
                       &lt;br /&gt;
&lt;br /&gt;
    # WARNING: update is called very frequently -- don&#039;t go crazy with logic&lt;br /&gt;
    # here.&lt;br /&gt;
    def update(self):&lt;br /&gt;
        try:&lt;br /&gt;
                        # if we don&#039;t have a socket, just return&lt;br /&gt;
                        if not self.sock: return&lt;br /&gt;
       &lt;br /&gt;
                        # without blocking, check for new connections&lt;br /&gt;
                        try:&lt;br /&gt;
                                conn, peeraddr = self.sock.accept()&lt;br /&gt;
                                self.peers.append(AdminConnection(self, conn, peeraddr))&lt;br /&gt;
                        except socket.error, detail:&lt;br /&gt;
                                if detail[0] != errno.EWOULDBLOCK:&lt;br /&gt;
                                        raise socket.error, detail&lt;br /&gt;
       &lt;br /&gt;
                        # update clients and mark connections that fail their update&lt;br /&gt;
                        disc = []&lt;br /&gt;
                        for client in self.peers:&lt;br /&gt;
                                if not client.update(): disc.append(client)&lt;br /&gt;
       &lt;br /&gt;
                        # delete any auth status for closed tcp connections&lt;br /&gt;
                        for d in disc:&lt;br /&gt;
                                if self.authed_sockets.has_key(d): del self.authed_sockets[d]&lt;br /&gt;
       &lt;br /&gt;
                        # now keep the remaining clients&lt;br /&gt;
                        self.peers = filter(lambda x: x not in disc, self.peers)&lt;br /&gt;
                except Exception, e:&lt;br /&gt;
                        printExceptionTrace(e, &#039;AdminServer.update&#039;)&lt;br /&gt;
&lt;br /&gt;
    def shutdown(self):&lt;br /&gt;
        try:&lt;br /&gt;
                        if self.sock:&lt;br /&gt;
                                self.sock.close()&lt;br /&gt;
                except Exception, e:&lt;br /&gt;
                        printExceptionTrace(e, &#039;AdminServer.shutdown&#039;)&lt;br /&gt;
                               &lt;br /&gt;
&lt;br /&gt;
    # Command implementations go here (member functions of the AdminServer)&lt;br /&gt;
&lt;br /&gt;
    # Allows a in-game rcon client to authenticate and get access.&lt;br /&gt;
    def rcmd_login(self, ctx, cmd):&lt;br /&gt;
        try:&lt;br /&gt;
                        success = 0&lt;br /&gt;
                        if ctx.isInGame():&lt;br /&gt;
                                # We&#039;re called by an in-game rcon client, use plain-text password&lt;br /&gt;
                                # (encoded into bf2 network stream).&lt;br /&gt;
                                if cmd.strip() == options[&#039;password&#039;]:&lt;br /&gt;
                                                self.authed_players[ctx.player] = 1&lt;br /&gt;
                                                success = 1&lt;br /&gt;
                                                print &#039;rcon: in-game client, player id: %s authenticated&#039; % str(ctx.player)&lt;br /&gt;
                                elif self.authed_players.has_key(ctx.player):&lt;br /&gt;
                                                del self.authed_players[ctx.player]&lt;br /&gt;
                        else:&lt;br /&gt;
                                # tcp client, require seeded digest to match instead of pw&lt;br /&gt;
                                if cmd.strip() == ctx.socket.correct_digest:&lt;br /&gt;
                                        self.authed_sockets[ctx.socket] = 1&lt;br /&gt;
                                        print &#039;rcon: tcp client from %s:%d logged on&#039; % ctx.socket.addr&lt;br /&gt;
                                        success = 1&lt;br /&gt;
                                else:&lt;br /&gt;
                                    if self.authed_sockets.has_key(ctx.socket):&lt;br /&gt;
                                        del self.authed_sockets[ctx.socket]&lt;br /&gt;
                                    print &#039;rcon: tcp client from %s:%d failed pw challenge&#039; % ctx.socket.addr&lt;br /&gt;
       &lt;br /&gt;
                        if success:&lt;br /&gt;
                                if ctx.isSocket():  # Added BF2CC June 13, 2005&lt;br /&gt;
                                        ctx.socket.bf2ccClient.RegisterClient(ctx.socket) # Added BF2CC June 13, 2005&lt;br /&gt;
                                       &lt;br /&gt;
                                ctx.write(&#039;Authentication successful, rcon ready.\n&#039;)&lt;br /&gt;
                        else:&lt;br /&gt;
                                ctx.write(&#039;Authentication failed.\n&#039;)&lt;br /&gt;
                except Exception, e:&lt;br /&gt;
                        printExceptionTrace(e, &#039;AdminServer.rcmd_login&#039;)&lt;br /&gt;
               &lt;br /&gt;
&lt;br /&gt;
    # Lists rcon-authenticated players.&lt;br /&gt;
    def rcmd_users(self, ctx, cmd):&lt;br /&gt;
        try:&lt;br /&gt;
                        ctx.write(&#039;active rcon users:\n&#039;)&lt;br /&gt;
                        for id in self.authed_players:&lt;br /&gt;
                                if id == -1:&lt;br /&gt;
                                        ctx.write(&#039;-1 (local server console)\n&#039;)&lt;br /&gt;
                                else:&lt;br /&gt;
                                        try:&lt;br /&gt;
                                                player = bf2.playerManager.getPlayerByIndex(id)&lt;br /&gt;
                                                ctx.write(&#039;%d from %s name=\&#039;%s\&#039;\n&#039; % (id, player.getAddress(), player.getName()))&lt;br /&gt;
                                        except:&lt;br /&gt;
                                                ctx.write(&#039;%d (no info)\n&#039; % (id))&lt;br /&gt;
       &lt;br /&gt;
                        for peer in self.authed_sockets:&lt;br /&gt;
                                ctx.write(&#039;tcp: %s:%d\n&#039; % (peer.addr[0], peer.addr[1]))&lt;br /&gt;
                except Exception, e:&lt;br /&gt;
                        printExceptionTrace(e, &#039;AdminServer.rcmd_users&#039;)&lt;br /&gt;
               &lt;br /&gt;
    # Executes a console command on the server.&lt;br /&gt;
    def rcmd_exec(self, ctx, cmd):&lt;br /&gt;
        try:&lt;br /&gt;
                        ctx.write(host.rcon_invoke(cmd))&lt;br /&gt;
                except Exception, e:&lt;br /&gt;
                        printExceptionTrace(e, &#039;AdminServer.rcmd_exec&#039;)&lt;br /&gt;
               &lt;br /&gt;
&lt;br /&gt;
    # Executes a bf2cc command on the server. Added BF2CC June 13, 2005&lt;br /&gt;
    def rcmd_bf2cc(self, ctx, cmd): # Added BF2CC June 13, 2005&lt;br /&gt;
                try:&lt;br /&gt;
                        ctx.socket.bf2ccClient.Exec(ctx, cmd) # Added BF2CC June 13, 2005&lt;br /&gt;
                except Exception, e:&lt;br /&gt;
                        printExceptionTrace(e, &#039;AdminServer.rcmd_bf2cc&#039;)&lt;br /&gt;
&lt;br /&gt;
    def rcmd_addPlayer(self, ctx, cmd):&lt;br /&gt;
        ctx.write(&#039;Adding player &#039; + cmd)&lt;br /&gt;
        standard_admin.kickoutsiders.addPlayerToList(cmd)&lt;br /&gt;
       &lt;br /&gt;
    def rcmd_removePlayer(self, ctx, cmd):&lt;br /&gt;
        ctx.write(&#039;Removing player &#039; + cmd)&lt;br /&gt;
        standard_admin.kickoutsiders.removePlayerFromList(cmd)&lt;br /&gt;
       &lt;br /&gt;
    def rcmd_changeMode(self, ctx, cmd):&lt;br /&gt;
        standard_admin.kickoutsiders.changeMode(cmd)&lt;br /&gt;
       &lt;br /&gt;
    def rcmd_currMode(self, ctx, cmd):&lt;br /&gt;
        standard_admin.kickoutsiders.writeMode(ctx)&lt;br /&gt;
       &lt;br /&gt;
    def rcmd_numFromList(self, ctx, cmd):&lt;br /&gt;
        standard_admin.kickoutsiders.writeNumList(ctx)&lt;br /&gt;
       &lt;br /&gt;
    def rcmd_isOnList(self, ctx, cmd):&lt;br /&gt;
        standard_admin.kickoutsiders.isOnList(cmd, ctx)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# parse the configuration file&lt;br /&gt;
parseConfig()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# our single server instance&lt;br /&gt;
server = AdminServer(int(options[&#039;port&#039;]))&lt;br /&gt;
&lt;br /&gt;
# These functions are called from the engine -- we implement them in terms of a&lt;br /&gt;
# class instance:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def init():&lt;br /&gt;
    print &#039;initializing default admin/rcon module&#039;&lt;br /&gt;
   &lt;br /&gt;
        try:&lt;br /&gt;
                # load (optional) admin scripts like teamkill punish and autobalance&lt;br /&gt;
                import standard_admin&lt;br /&gt;
        except Exception, e:&lt;br /&gt;
                printExceptionTrace(e, &#039;default.py.init&#039;)&lt;br /&gt;
&lt;br /&gt;
def shutdown():&lt;br /&gt;
    if server:&lt;br /&gt;
        print &#039;shutting down default admin/rcon module&#039;&lt;br /&gt;
        server.shutdown()&lt;br /&gt;
&lt;br /&gt;
def update():&lt;br /&gt;
    if server: server.update()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Pireax</name></author>
	</entry>
	<entry>
		<id>https://bf2tech.uturista.pt/index.php?title=Scripts:ReservedSlots&amp;diff=99</id>
		<title>Scripts:ReservedSlots</title>
		<link rel="alternate" type="text/html" href="https://bf2tech.uturista.pt/index.php?title=Scripts:ReservedSlots&amp;diff=99"/>
		<updated>2018-06-22T15:22:58Z</updated>

		<summary type="html">&lt;p&gt;Pireax: Created page with &amp;quot;A small script to make sure there will always be a few reserved slots for certain players. If a non approved nick logs on and the server has reached its limit, that player wil...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;A small script to make sure there will always be a few reserved slots for certain players. If a non approved nick logs on and the server has reached its limit, that player will be kicked immediately.&lt;br /&gt;
&lt;br /&gt;
This script should be run as the autobalance.py and tk_punish.py scripts in the standard_admin folder, which means change the __init__.py file to include this script.&lt;br /&gt;
&lt;br /&gt;
The script is very simple, but works well. Later I might add useful bits, like not having to modify the script to approve players or change the player threshold. Also I might change the player threshold to be more dynamic, not counting approved players in the total.&lt;br /&gt;
&lt;br /&gt;
In its current form below, the nicks PLAYER1, PLAYER2 and PLAYER3 will be the only people allowed on the server once 24 players are already present.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt; &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt; &amp;lt;/code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
  # Reserved slots system for Battlefield 2&lt;br /&gt;
  # Martin Ostergaard &amp;lt;monstergod@gmail.com&amp;gt; - 2005&lt;br /&gt;
 &lt;br /&gt;
  import bf2&lt;br /&gt;
  import host&lt;br /&gt;
  from bf2 import g_debug&lt;br /&gt;
 &lt;br /&gt;
  APPROVED_PLAYERS = [&#039;PLAYER1&#039;, &#039;PLAYER2&#039;, &#039;PLAYER3&#039;]&lt;br /&gt;
  MAX_PLAYERS = 24&lt;br /&gt;
 &lt;br /&gt;
  def init():&lt;br /&gt;
     host.registerHandler(&#039;PlayerConnect&#039;, resPlayerConnect, 1)&lt;br /&gt;
     host.registerHandler(&#039;PlayerDeath&#039;, resPlayerDeath, 1)#Added by Milton&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
  def resPlayerConnect(p):&lt;br /&gt;
     ONLINEPLAYERS = len(bf2.playerManager.getPlayers())&lt;br /&gt;
    &lt;br /&gt;
     if ONLINEPLAYERS &amp;gt; MAX_PLAYERS:&lt;br /&gt;
        if APPROVED_PLAYERS.count(p.getName()) &amp;lt; 1:&lt;br /&gt;
           host.rcon_invoke(&#039;admin.kickPlayer &#039; + str(p.index))&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Added by Milton&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  def resPlayerDeath(p, vehicle):&lt;br /&gt;
      ONLINEPLAYERS = len(bf2.playerManager.getPlayers())&lt;br /&gt;
      name = p.getName()&lt;br /&gt;
      if ONLINEPLAYERS &amp;gt; MAX_PLAYERS:&lt;br /&gt;
          if APPROVED_PLAYERS.count(p.getName()) &amp;lt; 1:&lt;br /&gt;
              host.rcon_invoke(&#039;PB_SV_Kick &#039; + name + &#039; 0 Sorry, making room for members&#039;)&lt;br /&gt;
              return&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note from underplay: Im busy right now, but it wouldnt be a bad idea to check to see if the approved players are already in the server..if they are all present, allow players to connect.&lt;br /&gt;
&lt;br /&gt;
Note from monsterdog: Very nice idea, and I have already changed the running version of it substantially, for instance I have added the capability to change the approved list in runtime. I will edit the script on these pages to reflect that once I&#039;m sure it runs smoothly.&lt;br /&gt;
&lt;br /&gt;
Note from bS: I like the idea of this script, one suggestion though. If you just setup one slot as permanently free? ea. you have a 32 player server and make it 33 slots. A player could always connect to the 33rd slot, when this happens an unapproved player would be kicked stating that he connected to a reserved slot; an approved player however will cause the script to kick an unapproved player who is already on the server and thus opening a new reserved slot to repeat the procedure in the future.&lt;br /&gt;
&lt;br /&gt;
Note from Mugzy: How about using a punkbuster kick so the kicked person can see why they were kicked?&lt;br /&gt;
&lt;br /&gt;
Note from Milton: In reply to bS, I modified it a bit so that it does exactly that, when an approved player joins the next person to die that is not approved gets kicked, however the punkbuster kick will not work right as the person joins, unfortunately it seems punkbuster doesn&#039;t recognize them untill they get into the server&lt;br /&gt;
&lt;br /&gt;
Note from monsterdog: Also the PB kick appearantly lags the server a bit everytime someone is kicked. I am deliberately putting off playing more with this script until patch 1.03 is out, where it is reportedly possible to kick with a specific message popping up over the server browser. I have an updated version of the script, however, which will let you change the approved list while the server is still running:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt; &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt; &amp;lt;/code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
# Reserved slots system for Battlefield 2&lt;br /&gt;
  # Martin Ostergaard - 2005&lt;br /&gt;
 &lt;br /&gt;
  import bf2&lt;br /&gt;
  import host&lt;br /&gt;
  import sys&lt;br /&gt;
  from bf2 import g_debug&lt;br /&gt;
 &lt;br /&gt;
  CONFIG_FILE = &#039;/home/bf2user/bf2/admin/standard_admin/approved_players.cfg&#039;&lt;br /&gt;
  MAX_PLAYERS = 20&lt;br /&gt;
 &lt;br /&gt;
  def init():&lt;br /&gt;
     print &#039;initializing reserved slots script&#039;&lt;br /&gt;
     host.registerHandler(&#039;PlayerConnect&#039;, resPlayerConnect, 1)&lt;br /&gt;
     sys.stdout.flush()&lt;br /&gt;
 &lt;br /&gt;
  def resPlayerConnect(p):&lt;br /&gt;
     onlineplayers = len(bf2.playerManager.getPlayers())&lt;br /&gt;
     new_player = p.getName()&lt;br /&gt;
 &lt;br /&gt;
     print new_player + &#039; connected, checking for a free slot&#039;&lt;br /&gt;
 &lt;br /&gt;
     if onlineplayers &amp;gt; MAX_PLAYERS:&lt;br /&gt;
        print &#039;unreserved player max reached, checking if &#039; + new_player + &#039; is approved&#039;&lt;br /&gt;
 &lt;br /&gt;
        CONFIG_FD = open(CONFIG_FILE)&lt;br /&gt;
        APPROVED_PLAYERS = CONFIG_FD.read()&lt;br /&gt;
        CONFIG_FD.close()&lt;br /&gt;
 &lt;br /&gt;
        if APPROVED_PLAYERS.count(new_player) &amp;gt; 0:&lt;br /&gt;
           print new_player + &#039; approved for login&#039;&lt;br /&gt;
        else:&lt;br /&gt;
           print new_player + &#039; not approved, will be kicked&#039;&lt;br /&gt;
           host.rcon_invoke(&#039;admin.kickPlayer &#039; + str(p.index))&lt;br /&gt;
 &lt;br /&gt;
     sys.stdout.flush()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;approved_players.cfg&amp;quot; is simply a text file, with each players nick on a line by itself, like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt; &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt; &amp;lt;/code&amp;gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
  PLAYER_1&lt;br /&gt;
  PLAYER_2&lt;br /&gt;
  PLAYER_N&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Make sure you do not add any empty lines or extra stuff in there. I am pretty certain it will still work if you apply Milton&#039;s changes to it. Also note that it actually sends some debugging information out, if you have enabled some kind of error outputting.&lt;br /&gt;
&lt;br /&gt;
Note by monsterdog: OK the above was a bit redundant, saw the new reserved slots script posted on this site, which basically does almost everything I had planned to do, very nice, use that instead :-)&lt;/div&gt;</summary>
		<author><name>Pireax</name></author>
	</entry>
	<entry>
		<id>https://bf2tech.uturista.pt/index.php?title=Scripts&amp;diff=98</id>
		<title>Scripts</title>
		<link rel="alternate" type="text/html" href="https://bf2tech.uturista.pt/index.php?title=Scripts&amp;diff=98"/>
		<updated>2018-06-22T15:22:11Z</updated>

		<summary type="html">&lt;p&gt;Pireax: Created page with &amp;quot;Please add your scripts to this list for others to see, use and get inspiration from:  __TOC__   == Access  ==  ; Scripts:ReservedSlots|Always Keep Slots Free for Special Pl...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Please add your scripts to this list for others to see, use and get inspiration from:&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Access  ==&lt;br /&gt;
&lt;br /&gt;
; [[Scripts:ReservedSlots|Always Keep Slots Free for Special Players]] (by monsterdog)&lt;br /&gt;
: When server reaches a certain number of players online, kick new players immediately unless they appear in an approved list.&lt;br /&gt;
&lt;br /&gt;
; [[Scripts:ReserveSlots|A Better Reserved Slots System]] (by Solarius)&lt;br /&gt;
: Uses a dynamic list of players (stored in a text file) to give certain players priority-- kicking people not on the list to make room (and kicking commanders/squad leaders as a last option).&lt;br /&gt;
&lt;br /&gt;
; [[Scripts:CountryFilter|CountryFilter]] (by Guwashi from [http://d3.jpn.org/ d3.jpn.org])&lt;br /&gt;
: Provides access control (allow/deny) based on player&#039;s country name.&lt;br /&gt;
&lt;br /&gt;
; [[Scripts:IdleKick|Kick Players Who Are Idle for a Configurable Time]] (by Xlr8or from [http://www.xlr8or.com/ www.xlr8or.com])&lt;br /&gt;
: Checks if players are actually playing or not. Warns once and then kicks them to free the slot.&lt;br /&gt;
&lt;br /&gt;
; [[Scripts:Kicking_for_high_ping|Kicking for High Ping]] (by Panic and Kybber from [http://www.battlefield.no/ Battlefield.no])&lt;br /&gt;
: Kicks high-pingers, based on a set of rules.&lt;br /&gt;
&lt;br /&gt;
==  Administration  ==&lt;br /&gt;
&lt;br /&gt;
; [[Scripts:dc_ass|Administrative Support System]] (by Butter from [http://dontcamp.com/ DontCamp.com])&lt;br /&gt;
: Provides an in-game chat based admin system similar to Kevin Lockitt&#039;s Battlefield Server Manager.&lt;br /&gt;
&lt;br /&gt;
; [[Scripts:Automatic_Announcements|Automatic Announcements]] (by Woody)&lt;br /&gt;
: Makes automatic periodic announcements to all players.&lt;br /&gt;
&lt;br /&gt;
; [[Scripts:AutoShutdown|Automatically Shutdown Server at Maintenance Time]] (by Greeze)&lt;br /&gt;
: A quick-and-dirty auto-shutdown script. Warns users at intervals before shutting down, and provides an option to either pause the game or quit the server.&lt;br /&gt;
&lt;br /&gt;
; [[Scripts:BadWords|Automatically Kick Players for Using Banned Words]] (by Woody)&lt;br /&gt;
: Automatically kicks players who use &amp;quot;inappropriate&amp;quot; language in chat messages, or in their player names.&lt;br /&gt;
&lt;br /&gt;
; [[Scripts:RconMap|Easily Change Map Through RCon]] (by biomass from [http://www.baconmen.net/ Clan BaconMen])&lt;br /&gt;
: Rcon &#039;map&#039; command to easily change maps on a server.&lt;br /&gt;
&lt;br /&gt;
; [[Scripts:RconCfg|Execute Commands from File]] (by truppo from [http://www.baconmen.net/ Clan BaconMen])&lt;br /&gt;
: Rcon &#039;cfg&#039; command to execute commands from file.&lt;br /&gt;
&lt;br /&gt;
; [[Scripts:BF2Admin|In-Game Administration Manager]] (by Danni)&lt;br /&gt;
: Provides the ability to flag users as administrators with varying levels of permissions. Help wanted!&lt;br /&gt;
&lt;br /&gt;
; [[Scripts:TXT_File_base_Automatic_Announcements|TXT File-Based Automatic Announcements]] (by daveml)&lt;br /&gt;
: Makes automatic periodic announcements to all players listed in a text file. Thanks to Woody for planting the seed :)&lt;br /&gt;
&lt;br /&gt;
==  Gameplay  ==&lt;br /&gt;
&lt;br /&gt;
; [[Scripts:AntiBaseRape|Anti-Base Rape]] (by SHAnders)&lt;br /&gt;
: Punishes player attacking a team within a specified radius of their uncaptuable controlpoint.&lt;br /&gt;
: The script is also available in Modmanager [[Scripts:AntiBaseRapeMM|format]] for bf2cc users. (by graag42)&lt;br /&gt;
&lt;br /&gt;
; [[Scripts:AutoMap|Automatic Map Changer/Randomizer]] (by dst from [http://dontcamp.com/ DontCamp.com])&lt;br /&gt;
: Automatically resizes maps based on players connected and randomizes the map cycle.&lt;br /&gt;
&lt;br /&gt;
; [[Scripts:Autoteam_by_Tickets|Autoteam by Ticket Ratio]] (by dst from [http://dontcamp.com/ DontCamp.com])&lt;br /&gt;
: Automatically adjusts sv.teamRatioPercent in inverse proportion to the ticket ratio.&lt;br /&gt;
&lt;br /&gt;
; [http://dev.vikingmind.com/c4punish c4punish](by BlackYoda from [http://www.vikingmind.com/ vikingmind.com])&lt;br /&gt;
: CTF game play mode add on to punish players who use C4 or Claymore mines near the main base flag. This script can be integrated with any CTF style Battlefield II gameplay mode, and is available now for Desert Conflict.&lt;br /&gt;
&lt;br /&gt;
; [[Scripts:SquadlessKick|Kick Squadless Players]] (by Sarc)&lt;br /&gt;
: Kicks players that are not commanding or in a squad. Performs the check on player spawn.&lt;br /&gt;
&lt;br /&gt;
; [[Scripts:MM_MapAutoSizer|ModManager Automatic Map Sizer]] (by [http://www.gloryhoundz.com/ GloryHoundz.com])&lt;br /&gt;
: This [ModManager ModManager] script will maintain the normal map rotation, but size the next map in rotation based on the number of players on the server.&lt;br /&gt;
&lt;br /&gt;
; [[Scripts:OfftimePy|OfftimePy]] (by [User:Dackz Dackz])&lt;br /&gt;
: Gives the ability to have seperate settings for when there are and aren&#039;t enough people to start a game.&lt;br /&gt;
&lt;br /&gt;
; [[Scripts:ClanTkProtection|Prevent Users from Punishing Your Clan Members]] (by underplay)&lt;br /&gt;
: Modifies the default tk punish script and prevents any members of your squad from being punished.&lt;br /&gt;
&lt;br /&gt;
; [http://www.filecloud.com/files/file.php?user_file_id=36666 Remove Flags on 64 Player Maps Based on Player Count] (by FBX)&lt;br /&gt;
: This script will remove some of the flags on all of the 64 player maps that have planes based on the number of players currently in the server. For example, if 20 people are playing, 3 flags may be removed depending on the map. If 40 people are playing maybe only 1 of the flags are removed. If 64 people are playing, none of the flags are removed. Please edit the script before using to accomodate your server. If you are running a map as the 32 or 16 player version and not the 64 player, you&#039;ll want to be sure to disable it in the script. Overwrites the old rules for conquest, so make a back-up first. Installing doesnt affect play outside your server and is server-side only.&lt;br /&gt;
&lt;br /&gt;
; [[Scripts:ThreatAndWorth|Threat and Worth]] (by SHAnders)&lt;br /&gt;
: Giving players bonus score based uppon a calculation of killer/vehicle worth vs victim/vehicle worth, overall threat rating and each players survival rating.&lt;br /&gt;
&lt;br /&gt;
; [[Scripts:BF2Oldschool|Weapon Restriction and Commander Detection (BF2 Oldschool infantry script)]] (by MisiekBest)&lt;br /&gt;
: This infantry script can: restrict some weapons on server (medics only, medics only with no unlocks, knife-pistol-shockpaddles only, no unlocks, no c4, no claymore, no mgs, no tow), kick or kill player for using restricted weapons, detect and kick commander (or just throw info). You can also manage script via rcon.&lt;br /&gt;
&lt;br /&gt;
; [[Scripts:Vehicle_Class_Limit|Vehicle Class Limit]] (by graag42)&lt;br /&gt;
: Prevents use of certain vehicle classes.&lt;br /&gt;
&lt;br /&gt;
; [[Scripts:Aircraft_Only|Aircraft Only]] (by polarity from [http://flightschool.polar-lights.org.uk/ Coop Flight School])&lt;br /&gt;
: Based on the above Vehicle Class Limit, this script is used to &#039;persuade&#039; all the players on the Coop Flight School server to play in aircraft only. Players who exit an aircraft they are spawned into are warned that they will start to take damage if they don&#039;t return to an aircraft in 25s. If they spawned outside an aircraft they are also warned to enter an aircraft. Prevents attempts to counter the damage by increasing damage rate if healing has occured.&lt;br /&gt;
&lt;br /&gt;
==  Miscellaneous  ==&lt;br /&gt;
&lt;br /&gt;
; [[Scripts:ConParser|ConParser]] (by FiRe- from [http://www.flmod.com/ flmod.com])&lt;br /&gt;
: A simple script to read and write BF-style Con-files.&lt;br /&gt;
&lt;br /&gt;
; [[Scripts:EvalPy|EvalPy]] (by Dackz)&lt;br /&gt;
: Allows evaluation of python statements over RCON in the context of the RCON script.&lt;br /&gt;
&lt;br /&gt;
; [[Scripts:EventsPy|EventsPy]] (by Dackz)&lt;br /&gt;
: Prints connection, disconnection, and chat events to the server console.&lt;br /&gt;
&lt;br /&gt;
; [[Scripts:PostUrl|Posting URL Lib]] (by MPUKBoffbowsh from [http://www.multiplay.co.uk/ Multiplay UK])&lt;br /&gt;
: Gives ability to HTTP POST a number of fields to a web page. Currently receives a garbled response, need to fix that.&lt;br /&gt;
&lt;br /&gt;
; [[Scripts:ReadingClanmembers|Reads Clanmembers from a File]] (by Nexus2k from [http://www.bs-dc.com/ bs-dc.com])&lt;br /&gt;
: Scriptpart for reading Clanmembers out of a members.cfg file&lt;br /&gt;
&lt;br /&gt;
; [[Scripts:UDP_Based_Advert_System|UDP-Based Advert System]] (by Panic and Kybber from [http://www.battlefield.no/ Battlefield.no])&lt;br /&gt;
: An idea of how one could utilize sockets to create an UDP based advert system.&lt;br /&gt;
&lt;br /&gt;
; [[Scripts:Player_Position_Display|Player Position Display]] (by polarity from [http://flightschool.polar-lights.org.uk/ Coop Flight School])&lt;br /&gt;
: For use as a tool when server side modding that can help with the positioning of vehicles/flags/spawn points. Displays the player&#039;s position and the direction that they&#039;re facing, in the same format as is used in the GamePlayObjects.con file.&lt;br /&gt;
&lt;br /&gt;
==  Modified Default Scripts  ==&lt;br /&gt;
&lt;br /&gt;
; [[Scripts:Enhanced_rotate_demo|Enhanced rotate_demo]] (by daveml)&lt;br /&gt;
: Additional logging for troubleshooting FTP, includes changes by dackz.&lt;br /&gt;
&lt;br /&gt;
; [http://www.filecloud.com/files/file.php?user_file_id=36152 Enhanced TK Script] (by FBX, McAfee)&lt;br /&gt;
: powerful TK script designed to replace the original (however keep a back up of the original anyways). Allows limiting of punishing from &amp;quot;static&amp;quot; weapons, such as AT mines, artillery, and claymores, and removal of punishing from heat seeking weapons, which are difficult to TK with intentially. Additionally, players can earn off punishings on their record by getting kills, or can instead use McAfee&#039;s system which only allows you to punish and allow a certain number of times you can be punished based on the number of kills you have. The amount of punishing on your record you have recieved resets at the end of a round. Script is by default silent. Installing doesnt affect online play outside your server and is server-side only.&lt;br /&gt;
: The script is also available in Modmanager [[Scripts:Enhanced_TK_Script_in_ModManager_format|format]] for bf2cc users. (by graag42)&lt;br /&gt;
&lt;br /&gt;
; [[Scripts:Modified_admin_script|Modified Admin Script (&#039;default.py&#039;)]] (by Panic and Kybber from [http://www.battlefield.no/ Battlefield.no])&lt;br /&gt;
: Enables logging to file and udp, and loads a settings file from the directory where the maplist is loaded from.&lt;br /&gt;
&lt;br /&gt;
; [[Scripts:ClanmemberBalance|Modified Autobalance Script]] (by Nexus2k from [http://www.bs-dc.com/ bs-dc.com])&lt;br /&gt;
: Prevents Clanmembers/Squadleaders/Commanders from Autobalance&lt;br /&gt;
&lt;br /&gt;
; [[Scripts:ModifiedDemoRotator|Modified Demo Rotator]] (by Dackz)&lt;br /&gt;
: Fixes moving to and from the same place causing problems, and chmods all demo files 0644 so they are web-readable.&lt;br /&gt;
&lt;br /&gt;
; [[Scripts:TK_punish_announcer|TK punish drop-in replacement]] (by Nadar, Kybber and Panic from [http://www.battlefield.no/ Battlefield.no])&lt;br /&gt;
: Announces the number of PTKs and FTKs a person has to prevent PTK-abuse. Does not modify the functionality of the original script, so it should be accepted as Ranked-server compatible.&lt;br /&gt;
&lt;br /&gt;
== Restart Server Scripts ==&lt;br /&gt;
&lt;br /&gt;
; [[Scripts:RestartScript|Restart Scripts]]&lt;br /&gt;
: Scripts To restart Your Server after Crash. --DarkPepe 18:38, 3 June 2006 (MDT)&lt;/div&gt;</summary>
		<author><name>Pireax</name></author>
	</entry>
</feed>