// Bomberman! - From the NES :)

/* CVARS - copy and paste to shconfig.cfg

//Bomberman
bomberman_level 0
bomberman_cooldown 5        //Cooldown time from bomb explostion until new planting
bomberman_bombs 1        //How Many Bombs does he start with           (def=1)
bomberman_bpl 0            //How Many More Bombs Does he get each level (def=0)
bomberman_radius 400        //Radius of damage            (def=400)
bomberman_maxdamage 100        //Maximum Damage to deal        (def=100)

*/

//Thanks to TheLooser & Demonic_Frost for help testing

#include <superheromod>

// GLOBAL VARIABLES
new gHeroID
new const gHeroName[] = "Bomberman"
new bool:gHasBomberman[SH_MAXSLOTS+1]
new gBombEntity[SH_MAXSLOTS+1]
new gBombAmmo[SH_MAXSLOTS+1]
new const gSoundBombPlant[] = "weapons/c4_plant.wav"
new gBombModel[32] = "models/shmod/bomberman_bomb.mdl"
new gSpriteSmoke, gSpriteWhite, gSpriteFire, gSpriteExplode
new gPcvarLevel, gPcvarCooldown, gPcvarBombs
new gPcvarBPL, gPcvarRadius, gPcvarMaxDamage
//----------------------------------------------------------------------------------------------
public plugin_init()
{
    // Plugin Info
    register_plugin("SUPERHERO Bomberman", SH_VERSION_STR, "AssKicR")

    register_dictionary("sh_bomberman.txt")

    // DO NOT EDIT THIS FILE TO CHANGE CVARS, USE THE SHCONFIG.CFG
    gPcvarLevel = register_cvar("bomberman_level", "0")
    gPcvarCooldown = register_cvar("bomberman_cooldown", "5")
    gPcvarBombs = register_cvar("bomberman_bombs", "1")
    gPcvarBPL = register_cvar("bomberman_bpl", "0")
    gPcvarRadius = register_cvar("bomberman_radius", "400")
    gPcvarMaxDamage = register_cvar("bomberman_maxdamage", "100")

    // FIRE THE EVENTS TO CREATE THIS SUPERHERO!
    gHeroID = sh_create_hero(gHeroName, gPcvarLevel)
    sh_set_hero_info(gHeroID, "Remote Bombs", "Press +power button to plant, and again to detonate")
    sh_set_hero_bind(gHeroID)
}
//----------------------------------------------------------------------------------------------
public plugin_precache()
{
    // What Skin Is The Bomb Gonna Have
    if ( !file_exists(gBombModel) ) {
        copy(gBombModel, charsmax(gBombModel), "models/w_c4.mdl")
    }

    precache_model(gBombModel)
    precache_sound(gSoundBombPlant)
    gSpriteExplode = precache_model("sprites/zerogxplode.spr")
    gSpriteSmoke = precache_model("sprites/steam1.spr")
    gSpriteWhite = precache_model("sprites/white.spr")
    gSpriteFire = precache_model("sprites/explode1.spr")
}
//----------------------------------------------------------------------------------------------
public sh_hero_init(id, heroID, mode)
{
    if ( gHeroID != heroID ) return

    switch(mode) {
        case SH_HERO_ADD: {
            gHasBomberman[id] = true
            bomberman_newsetup(id)
        }
        case SH_HERO_DROP: {
            gHasBomberman[id] = false
        }
    }

    sh_debug_message(id, 1, "%s %s", gHeroName, mode ? "ADDED" : "DROPPED")
}
//----------------------------------------------------------------------------------------------
public sh_client_spawn(id)
{
    bomberman_newsetup(id)
}
//----------------------------------------------------------------------------------------------
bomberman_newsetup(id)
{
    gPlayerInCooldown[id] = false

    if ( !gHasBomberman[id] ) return

    new bombent = gBombEntity[id]

    if ( pev_valid(bombent) ) {
        engfunc(EngFunc_RemoveEntity, bombent)
    }

    gBombEntity[id] = 0

    new bombsPerLvl = get_pcvar_num(gPcvarBPL)

    if ( bombsPerLvl > 0 ) {
        //new bombs=((level he is - level he must be) * bombs per level) + starting bombs
        new bombs = ((sh_get_user_lvl(id)-get_pcvar_num(gPcvarLevel)) * bombsPerLvl + get_pcvar_num(gPcvarBombs))

        if ( bombs > 0 ) {
            gBombAmmo[id] = bombs
        }
        else if ( bombs == 0 ) {
            gBombAmmo[id] = 1
        }
        else {
            gBombAmmo[id] = 0
        }
    }
    else {
        gBombAmmo[id] = get_pcvar_num(gPcvarBombs)
    }
}
//----------------------------------------------------------------------------------------------
// RESPOND TO KEYDOWN
public sh_hero_key(id, heroID, key)
{
    if ( gHeroID != heroID || sh_is_freezetime() ) return
    if ( !is_user_alive(id) || !gHasBomberman[id] ) return

    if ( key == SH_KEYDOWN ) {
        if ( gBombEntity[id] > 0 ) {
            explode_bomb(id)
        }
        else {
            plant_bomb(id)
        }
    }
}
//----------------------------------------------------------------------------------------------
plant_bomb(id)
{
    if ( gBombEntity[id] > 0 ) return

    if ( gBombAmmo[id] == 0 ) {
        sh_sound_deny(id)
        client_print(id, print_center, "[SH] %L", LANG_PLAYER, "SH_BOMBERMAN_YH")
        return
    }

    if ( gPlayerInCooldown[id]) {
        sh_sound_deny(id)
        return
    }

    new bombent
    gBombEntity[id] = bombent = engfunc(EngFunc_CreateNamedEntity, engfunc(EngFunc_AllocString, "info_target"))

    if ( !pev_valid(bombent) ) {
        gBombEntity[id] = 0
        return
    }

    set_pev(bombent, pev_classname, "remote_bomb")
    engfunc(EngFunc_SetModel, bombent, gBombModel)

    new Float:PlayerOrigin[3]
    pev(id, pev_origin, PlayerOrigin)

    engfunc(EngFunc_SetSize, bombent, Float:{-4.0, -4.0, 2.0}, Float:{4.0, 4.0, 10.0})
    engfunc(EngFunc_SetOrigin, bombent, PlayerOrigin)
    set_pev(bombent, pev_solid, SOLID_NOT)        //Maybe change this to SOLID_BBOX later
    set_pev(bombent, pev_movetype, MOVETYPE_TOSS)
    set_pev(bombent, pev_owner, id)

    emit_sound(bombent, CHAN_WEAPON, gSoundBombPlant, VOL_NORM, ATTN_NORM, 0, PITCH_NORM)

    gBombAmmo[id]--
    client_print(id, print_center, "[SH] %L", LANG_PLAYER, "SH_BOMBERMAN_BP", gBombAmmo[id], gBombAmmo[id] == 1 ? "" : "s")
}
//----------------------------------------------------------------------------------------------
explode_bomb(id)
{
    new bombent = gBombEntity[id]

    if ( pev_valid(bombent) ) {

        sh_set_cooldown(id, get_pcvar_float(gPcvarCooldown))

        new Float:explodeAt[3]
        pev(bombent, pev_origin, explodeAt)

        blow_up(id, explodeAt)

        message_begin(MSG_BROADCAST, SVC_TEMPENTITY)
        write_byte(TE_EXPLOSION)
        engfunc(EngFunc_WriteCoord, explodeAt[0])
        engfunc(EngFunc_WriteCoord, explodeAt[1])
        engfunc(EngFunc_WriteCoord, explodeAt[2])
        write_short(gSpriteExplode)
        write_byte(50)
        write_byte(15)
        write_byte(0)
        message_end()

        engfunc(EngFunc_RemoveEntity, bombent)
    }

    gBombEntity[id] = 0
}
//----------------------------------------------------------------------------------------------
blow_up(id, Float:explodeAt[3])
{
    new Float:dRatio, damage, Float:distanceBetween
    new Float:dmgRadius = get_pcvar_float(gPcvarRadius)
    new maxDamage = get_pcvar_num(gPcvarMaxDamage)
    new bool:FFOn = sh_friendlyfire_on()
    new CsTeams:idTeam = cs_get_user_team(id)

    // blowup
    explode(explodeAt)

    new players[SH_MAXSLOTS], playerCount, player
    new Float:playerOrigin[3]

    get_players(players, playerCount, "ah")

    for ( new i = 0; i < playerCount; i++ ) {
        player = players[i]

        pev(player, pev_origin, playerOrigin)
        distanceBetween = vector_distance(explodeAt, playerOrigin)

        if ( distanceBetween <= dmgRadius ) {
            if ( FFOn || player == id || idTeam != cs_get_user_team(player) ) {
                dRatio = distanceBetween / dmgRadius
                damage = maxDamage - floatround(maxDamage * dRatio)
                if ( !damage ) damage = 1    // Incase damage cvar is really low cause something if within the radius 
                sh_extra_damage(player, id, damage, "bomberman bomb", _, SH_DMG_NORM, true, _, explodeAt)
            }

            // Add some push and shake effects instead of dmgStun later, and cause it on everyone within radius
        }
    }
}
//----------------------------------------------------------------------------------------------
explode(Float:explodeAt[3])
{
    // Raise the effects up a bit
    explodeAt[2] += 37.0

    // blast circles
    engfunc(EngFunc_MessageBegin, MSG_BROADCAST, SVC_TEMPENTITY, explodeAt, 0)
    write_byte(TE_BEAMCYLINDER)    // 21
    engfunc(EngFunc_WriteCoord, explodeAt[0])
    engfunc(EngFunc_WriteCoord, explodeAt[1])
    engfunc(EngFunc_WriteCoord, explodeAt[2] + 16.0)
    engfunc(EngFunc_WriteCoord, explodeAt[0])
    engfunc(EngFunc_WriteCoord, explodeAt[1])
    engfunc(EngFunc_WriteCoord, explodeAt[2] + 1936.0)
    write_short(gSpriteWhite)
    write_byte(0)        // startframe
    write_byte(0)        // framerate
    write_byte(2)        // life
    write_byte(20)        // width
    write_byte(0)        // noise
    write_byte(188)        // r
    write_byte(220)        // g
    write_byte(255)        // b
    write_byte(255)        // brightness
    write_byte(0)        // speed
    message_end()

    //Explosion2
    message_begin(MSG_BROADCAST, SVC_TEMPENTITY)
    write_byte(TE_EXPLOSION2)    // 12
    engfunc(EngFunc_WriteCoord, explodeAt[0])
    engfunc(EngFunc_WriteCoord, explodeAt[1])
    engfunc(EngFunc_WriteCoord, explodeAt[2])
    write_byte(188)        // scale in 0.1's
    write_byte(10)        // framerate
    message_end()

    //TE_Explosion
    engfunc(EngFunc_MessageBegin, MSG_BROADCAST, SVC_TEMPENTITY, explodeAt, 0)
    write_byte(TE_EXPLOSION)    // 3
    engfunc(EngFunc_WriteCoord, explodeAt[0])
    engfunc(EngFunc_WriteCoord, explodeAt[1])
    engfunc(EngFunc_WriteCoord, explodeAt[2])
    write_short(gSpriteFire)
    write_byte(60)        // scale in 0.1's
    write_byte(10)        // framerate
    write_byte(0)        // flags
    message_end()

    //Smoke
    engfunc(EngFunc_MessageBegin, MSG_BROADCAST, SVC_TEMPENTITY, explodeAt, 0)
    write_byte(TE_SMOKE)        // 5
    engfunc(EngFunc_WriteCoord, explodeAt[0])
    engfunc(EngFunc_WriteCoord, explodeAt[1])
    engfunc(EngFunc_WriteCoord, explodeAt[2])
    write_short(gSpriteSmoke)
    write_byte(10)        // scale in 0.1's
    write_byte(10)        // framerate
    message_end()
}
//----------------------------------------------------------------------------------------------
public client_connect(id)
{
    new bombent = gBombEntity[id]

    if ( pev_valid(bombent) ) {
        engfunc(EngFunc_RemoveEntity, bombent)
    }

    gBombEntity[id] = 0
    gPlayerInCooldown[id] = false
    gHasBomberman[id] = false
}
//----------------------------------------------------------------------------------------------
public client_disconnected(id)
{
    new bombent = gBombEntity[id]

    if ( pev_valid(bombent) ) {
        engfunc(EngFunc_RemoveEntity, bombent)
    }

    gBombEntity[id] = 0
    gPlayerInCooldown[id] = false
    gHasBomberman[id] = false
}
//----------------------------------------------------------------------------------------------