Raised This Month: $32 Target: $400
 8% 

Doing ladder


Post New Thread Reply   
 
Thread Tools Display Modes
Exolent[jNr]
Veteran Member
Join Date: Feb 2007
Location: Tennessee
Old 12-18-2008 , 13:03   Re: Doing ladder
Reply With Quote #11

Sorry, I can't watch right now since I am at school.
And I won't be able to until a couple hours later from now.
__________________
No private work or selling mods.
Quote:
Originally Posted by xPaw View Post
I love you exolent!
Exolent[jNr] is offline
Dores
Veteran Member
Join Date: Jun 2008
Location: You really don't wanna k
Old 12-18-2008 , 15:23   Re: Doing ladder
Reply With Quote #12

Damn, Exolent, from where do you know that much of velocity, aim velocity and stuff? I didn't understand half of what you did! So jealous...
I don't know how to handle arrays like you...
__________________
O o
/¯________________________
| IMMA FIRIN' MAH LAZOR!!!
\_¯¯¯
Dores is offline
Exolent[jNr]
Veteran Member
Join Date: Feb 2007
Location: Tennessee
Old 12-18-2008 , 15:52   Re: Doing ladder
Reply With Quote #13

I sent Dores a PM explaining how I did all of that work.
If anyone else wants to know, take a look here.

EDIT: LOL! I just watched the demo. I'll see what I can do.

EDIT2: I fixed it.
The problem was that velocity[] was static, which means it never reset.
Which also means that the velocity was constantly added, which gave enormous speeds.
I tested it myself, and it seems to work pretty well:

Redownload
__________________
No private work or selling mods.
Quote:
Originally Posted by xPaw View Post
I love you exolent!

Last edited by Exolent[jNr]; 12-18-2008 at 16:32.
Exolent[jNr] is offline
minimiller
Veteran Member
Join Date: Aug 2007
Location: United Kingdom
Old 12-18-2008 , 16:46   Re: Doing ladder
Reply With Quote #14

Nice job!
It works, but i cant be bothered to Dload the ladder.mdl, so i renamed "cow.mdl" this was the result:

__________________

Last edited by minimiller; 12-27-2008 at 14:46.
minimiller is offline
Send a message via MSN to minimiller
stupok
Veteran Member
Join Date: Feb 2006
Old 12-18-2008 , 19:53   Re: Doing ladder
Reply With Quote #15

w00t nice job duders, I might have a look later on
__________________
stupok is offline
xPaw
Retired AMX Mod X Moderator
Join Date: Jul 2008
Old 12-22-2008 , 04:36   Re: Doing ladder
Reply With Quote #16

connor how going your ladder?
__________________
xPaw is offline
ConnorMcLeod
Veteran Member
Join Date: Jul 2006
Location: France (95)
Old 12-22-2008 , 04:40   Re: Doing ladder
Reply With Quote #17

Stand by.

Was simply copy/pasting laddermove code from HLSDK, gonna share what i'v done so anyone can work on it.

Code:
void PM_LadderMove( physent_t *pLadder )
{
	vec3_t		ladderCenter;
	trace_t		trace;
	qboolean	onFloor;
	vec3_t		floor;
	vec3_t		modelmins, modelmaxs;

	if ( pmove->movetype == MOVETYPE_NOCLIP )
		return;

	pmove->PM_GetModelBounds( pLadder->model, modelmins, modelmaxs );

	VectorAdd( modelmins, modelmaxs, ladderCenter );
	VectorScale( ladderCenter, 0.5, ladderCenter );

	pmove->movetype = MOVETYPE_FLY;

	// On ladder, convert movement to be relative to the ladder

	VectorCopy( pmove->origin, floor );
	floor[2] += pmove->player_mins[pmove->usehull][2] - 1;

	if ( pmove->PM_PointContents( floor, NULL ) == CONTENTS_SOLID )
		onFloor = true;
	else
		onFloor = false;

	pmove->gravity = 0;
	pmove->PM_TraceModel( pLadder, pmove->origin, ladderCenter, &trace );
	if ( trace.fraction != 1.0 )
	{
		float forward = 0, right = 0;
		vec3_t vpn, v_right;

		AngleVectors( pmove->angles, vpn, v_right, NULL );
		if ( pmove->cmd.buttons & IN_BACK )
			forward -= MAX_CLIMB_SPEED;
		if ( pmove->cmd.buttons & IN_FORWARD )
			forward += MAX_CLIMB_SPEED;
		if ( pmove->cmd.buttons & IN_MOVELEFT )
			right -= MAX_CLIMB_SPEED;
		if ( pmove->cmd.buttons & IN_MOVERIGHT )
			right += MAX_CLIMB_SPEED;

		if ( pmove->cmd.buttons & IN_JUMP )
		{
			pmove->movetype = MOVETYPE_WALK;
			VectorScale( trace.plane.normal, 270, pmove->velocity );
		}
		else
		{
			if ( forward != 0 || right != 0 )
			{
				vec3_t velocity, perp, cross, lateral, tmp;
				float normal;

				//ALERT(at_console, "pev %.2f %.2f %.2f - ",
				//	pev->velocity.x, pev->velocity.y, pev->velocity.z);
				// Calculate player's intended velocity
				//Vector velocity = (forward * gpGlobals->v_forward) + (right * gpGlobals->v_right);
				VectorScale( vpn, forward, velocity );
				VectorMA( velocity, right, v_right, velocity );

				
				// Perpendicular in the ladder plane
	//					Vector perp = CrossProduct( Vector(0,0,1), trace.vecPlaneNormal );
	//					perp = perp.Normalize();
				VectorClear( tmp );
				tmp[2] = 1;
				CrossProduct( tmp, trace.plane.normal, perp );
				VectorNormalize( perp );


				// decompose velocity into ladder plane
				normal = DotProduct( velocity, trace.plane.normal );
				// This is the velocity into the face of the ladder
				VectorScale( trace.plane.normal, normal, cross );


				// This is the player's additional velocity
				VectorSubtract( velocity, cross, lateral );

				// This turns the velocity into the face of the ladder into velocity that
				// is roughly vertically perpendicular to the face of the ladder.
				// NOTE: It IS possible to face up and move down or face down and move up
				// because the velocity is a sum of the directional velocity and the converted
				// velocity through the face of the ladder -- by design.
				CrossProduct( trace.plane.normal, perp, tmp );
				VectorMA( lateral, -normal, tmp, pmove->velocity );
				if ( onFloor && normal > 0 )	// On ground moving away from the ladder
				{
					VectorMA( pmove->velocity, MAX_CLIMB_SPEED, trace.plane.normal, pmove->velocity );
				}
				//pev->velocity = lateral - (CrossProduct( trace.vecPlaneNormal, perp ) * normal);
			}
			else
			{
				VectorClear( pmove->velocity );
			}
		}
	}
}
PHP Code:
/*    Copyright © 2008, ConnorMcLeod

    Ladder Test is free software;
    you can redistribute it and/or modify it under the terms of the
    GNU General Public License as published by the Free Software Foundation.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Ladder Test; if not, write to the
    Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.
*/

#include <amxmodx>
#include <fakemeta>
#include <hamsandwich>
#include <xs>

#define PLUGIN "Ladder Test"
#define AUTHOR "ConnorMcLeod"
#define VERSION "0.0.1"

#define MAX_CLIMB_SPEED    200.0

new gOnLadder[33];

public 
plugin_init()
{
    
register_plugin(PLUGINVERSIONAUTHOR)

    
RegisterHam(Ham_Touch"func_wall""World_Touch")
    
RegisterHam(Ham_Touch"func_breakable""World_Touch")
//    RegisterHam(Ham_Touch, "worldspawn", "World_Touch")

    
register_forwardFM_PlayerPostThink "PlayerPostThink")
}

public 
World_Touch(iEntid)
{
    if( !
is_user_alive(id) )
    {
        return
    }

    if( 
pev(idpev_groundentity) == iEnt )
    {
            return
    }
    
gOnLadder[id] = iEnt
}

public 
PlayerPostThink(id)
{
    if( !
gOnLadder[id] || pev(idpev_movetype) == MOVETYPE_NOCLIP)
    {
        return
    }

    static 
pLadder pLadder gOnLadder[id]
    static 
bool:onFloor
    
static Float:modelmins[3], Float:modelmaxs[3], Float:ladderCenter[3], Float:floor[3],
    
Float:origin[3]

    
pev(pLadderpev_minsmodelmins)
    
pev(pLadderpev_maxsmodelmaxs)
    
xs_vec_addmodelminsmodelmaxsladderCenter );
    
xs_vec_mul_scalarladderCenter0.5ladderCenter );

    
set_pev(idpev_movetypeMOVETYPE_FLY)

    
pevidpev_originorigin )
    
xs_vec_copy(originfloor)
    
pev(idpev_minsmodelmins)
    
floor[2] += modelmins[2] - 1

    
if ( engfuncEngFunc_PointContentsfloor ) == CONTENTS_SOLID )
        
onFloor true;
    else
        
onFloor false;

    
//set_pev(id, pev_gravity, 0.0) // useless ?

    //PM_TraceModel( pLadder, pmove->origin, ladderCenter, &trace )
//    engfunc(EngFunc_TraceModel, origin, ladderCenter, HULL_HUMAN, pLadder, 0);

    
static Float:flTraceFraction
    global_get
glb_trace_fractionflTraceFraction )
    if ( 
flTraceFraction == 1.0 )
        return

    static 
iButton iButton pev(idpev_button)
    static 
Float:flVelocity[3]

    static 
Float:_forwardFloat:right
    
static Float:vpn[3], Float:v_right[3];
    
_forward 0.0
    right 
0.0

    
new Float:flAngles[3]
    
pev(idpev_anglesflAngles)
    
engfunc(EngFunc_AngleVectorsflAnglesvpnv_right0.0);

    if ( 
iButton IN_BACK )
        
_forward -= MAX_CLIMB_SPEED;
    if ( 
iButton IN_FORWARD )
        
_forward += MAX_CLIMB_SPEED;
    if ( 
iButton IN_MOVELEFT )
        
right -= MAX_CLIMB_SPEED;
    if ( 
iButton IN_MOVERIGHT )
        
right += MAX_CLIMB_SPEED;

    new 
Float:flTracePlaneNormal[3]
    if ( 
iButton IN_JUMP )
    {
        
set_pev(idpev_movetypeMOVETYPE_WALK)
        
global_get(glb_trace_plane_normalflTracePlaneNormal)        
        
xs_vec_mul_scalar(flTracePlaneNormal270.0flVelocity)
        
set_pev(idpev_velocityflVelocity)
    }
    else
    {
        if( 
_forward || right )
        {
            static 
Float:velocity[3], Float:perp[3], Float:cross[3], Float:lateral[3], Float:tmp[3]
            static 
Float:normal

            xs_vec_mul_scalar
(vpn_forwardvelocity)
            
VectorMAvelocityrightv_rightvelocity )

            
tmp[0] = 0.0
            tmp
[1] = 0.0
            tmp
[2] = 1.0;
            
global_get(glb_trace_plane_normalflTracePlaneNormal)
            
xs_vec_crosstmpflTracePlaneNormalperp );
            
xs_vec_normalize(perpperp)

            
// decompose velocity into ladder plane
            
normal xs_vec_dotvelocityflTracePlaneNormal );
            
            
// This is the velocity into the face of the ladder
            
xs_vec_mul_scalar(flTracePlaneNormalnormalcross)

            
// This is the player's additional velocity
            
xs_vec_subvelocitycrosslateral );

            
// This turns the velocity into the face of the ladder into velocity that
            // is roughly vertically perpendicular to the face of the ladder.
            // NOTE: It IS possible to face up and move down or face down and move up
            // because the velocity is a sum of the directional velocity and the converted
            // velocity through the face of the ladder -- by design.
            
xs_vec_cross(flTracePlaneNormalperptmp)
            
VectorMAlateral, -normaltmpvelocity );
            
            if ( 
onFloor && normal )    // On ground moving away from the ladder
            
{
                
VectorMAvelocityMAX_CLIMB_SPEEDflTracePlaneNormalvelocity );
            }
            
set_pev(idpev_velocityvelocity)
        }
        else
        {
            
set_pev(idpev_velocityFloat:{0.0,0.0,0.0})
            return
        }
    }
    
gOnLadder[id] = 0
}

VectorMA(const Float:veca[3], Float:scale, const Float:vecb[3], Float:vecc[3])
{
    
vecc[0] = veca[0] + scale*vecb[0];
    
vecc[1] = veca[1] + scale*vecb[1];
    
vecc[2] = veca[2] + scale*vecb[2];

__________________
- tired and retired -

- my plugins -
ConnorMcLeod is offline
koleos
Senior Member
Join Date: Jul 2008
Old 03-09-2009 , 21:04   Re: Doing ladder
Reply With Quote #18

Quote:
Originally Posted by ConnorMcLeod View Post
Stand by.

Was simply copy/pasting laddermove code from HLSDK, gonna share what i'v done so anyone can work on it.

Code:
void PM_LadderMove( physent_t *pLadder )
{
    vec3_t        ladderCenter;
    trace_t        trace;
    qboolean    onFloor;
    vec3_t        floor;
    vec3_t        modelmins, modelmaxs;

    if ( pmove->movetype == MOVETYPE_NOCLIP )
        return;

    pmove->PM_GetModelBounds( pLadder->model, modelmins, modelmaxs );

    VectorAdd( modelmins, modelmaxs, ladderCenter );
    VectorScale( ladderCenter, 0.5, ladderCenter );

    pmove->movetype = MOVETYPE_FLY;

    // On ladder, convert movement to be relative to the ladder

    VectorCopy( pmove->origin, floor );
    floor[2] += pmove->player_mins[pmove->usehull][2] - 1;

    if ( pmove->PM_PointContents( floor, NULL ) == CONTENTS_SOLID )
        onFloor = true;
    else
        onFloor = false;

    pmove->gravity = 0;
    pmove->PM_TraceModel( pLadder, pmove->origin, ladderCenter, &trace );
    if ( trace.fraction != 1.0 )
    {
        float forward = 0, right = 0;
        vec3_t vpn, v_right;

        AngleVectors( pmove->angles, vpn, v_right, NULL );
        if ( pmove->cmd.buttons & IN_BACK )
            forward -= MAX_CLIMB_SPEED;
        if ( pmove->cmd.buttons & IN_FORWARD )
            forward += MAX_CLIMB_SPEED;
        if ( pmove->cmd.buttons & IN_MOVELEFT )
            right -= MAX_CLIMB_SPEED;
        if ( pmove->cmd.buttons & IN_MOVERIGHT )
            right += MAX_CLIMB_SPEED;

        if ( pmove->cmd.buttons & IN_JUMP )
        {
            pmove->movetype = MOVETYPE_WALK;
            VectorScale( trace.plane.normal, 270, pmove->velocity );
        }
        else
        {
            if ( forward != 0 || right != 0 )
            {
                vec3_t velocity, perp, cross, lateral, tmp;
                float normal;

                //ALERT(at_console, "pev %.2f %.2f %.2f - ",
                //    pev->velocity.x, pev->velocity.y, pev->velocity.z);
                // Calculate player's intended velocity
                //Vector velocity = (forward * gpGlobals->v_forward) + (right * gpGlobals->v_right);
                VectorScale( vpn, forward, velocity );
                VectorMA( velocity, right, v_right, velocity );

                
                // Perpendicular in the ladder plane
    //                    Vector perp = CrossProduct( Vector(0,0,1), trace.vecPlaneNormal );
    //                    perp = perp.Normalize();
                VectorClear( tmp );
                tmp[2] = 1;
                CrossProduct( tmp, trace.plane.normal, perp );
                VectorNormalize( perp );


                // decompose velocity into ladder plane
                normal = DotProduct( velocity, trace.plane.normal );
                // This is the velocity into the face of the ladder
                VectorScale( trace.plane.normal, normal, cross );


                // This is the player's additional velocity
                VectorSubtract( velocity, cross, lateral );

                // This turns the velocity into the face of the ladder into velocity that
                // is roughly vertically perpendicular to the face of the ladder.
                // NOTE: It IS possible to face up and move down or face down and move up
                // because the velocity is a sum of the directional velocity and the converted
                // velocity through the face of the ladder -- by design.
                CrossProduct( trace.plane.normal, perp, tmp );
                VectorMA( lateral, -normal, tmp, pmove->velocity );
                if ( onFloor && normal > 0 )    // On ground moving away from the ladder
                {
                    VectorMA( pmove->velocity, MAX_CLIMB_SPEED, trace.plane.normal, pmove->velocity );
                }
                //pev->velocity = lateral - (CrossProduct( trace.vecPlaneNormal, perp ) * normal);
            }
            else
            {
                VectorClear( pmove->velocity );
            }
        }
    }
}
PHP Code:
/*    Copyright © 2008, ConnorMcLeod

    Ladder Test is free software;
    you can redistribute it and/or modify it under the terms of the
    GNU General Public License as published by the Free Software Foundation.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Ladder Test; if not, write to the
    Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.
*/

#include <amxmodx>
#include <fakemeta>
#include <hamsandwich>
#include <xs>

#define PLUGIN "Ladder Test"
#define AUTHOR "ConnorMcLeod"
#define VERSION "0.0.1"

#define MAX_CLIMB_SPEED    200.0

new gOnLadder[33];

public 
plugin_init()
{
    
register_plugin(PLUGINVERSIONAUTHOR)

    
RegisterHam(Ham_Touch"func_wall""World_Touch")
    
RegisterHam(Ham_Touch"func_breakable""World_Touch")
//    RegisterHam(Ham_Touch, "worldspawn", "World_Touch")

    
register_forwardFM_PlayerPostThink "PlayerPostThink")
}

public 
World_Touch(iEntid)
{
    if( !
is_user_alive(id) )
    {
        return
    }

    if( 
pev(idpev_groundentity) == iEnt )
    {
            return
    }
    
gOnLadder[id] = iEnt
}

public 
PlayerPostThink(id)
{
    if( !
gOnLadder[id] || pev(idpev_movetype) == MOVETYPE_NOCLIP)
    {
        return
    }

    static 
pLadder pLadder gOnLadder[id]
    static 
bool:onFloor
    
static Float:modelmins[3], Float:modelmaxs[3], Float:ladderCenter[3], Float:floor[3],
    
Float:origin[3]

    
pev(pLadderpev_minsmodelmins)
    
pev(pLadderpev_maxsmodelmaxs)
    
xs_vec_addmodelminsmodelmaxsladderCenter );
    
xs_vec_mul_scalarladderCenter0.5ladderCenter );

    
set_pev(idpev_movetypeMOVETYPE_FLY)

    
pevidpev_originorigin )
    
xs_vec_copy(originfloor)
    
pev(idpev_minsmodelmins)
    
floor[2] += modelmins[2] - 1

    
if ( engfuncEngFunc_PointContentsfloor ) == CONTENTS_SOLID )
        
onFloor true;
    else
        
onFloor false;

    
//set_pev(id, pev_gravity, 0.0) // useless ?

    //PM_TraceModel( pLadder, pmove->origin, ladderCenter, &trace )
//    engfunc(EngFunc_TraceModel, origin, ladderCenter, HULL_HUMAN, pLadder, 0);

    
static Float:flTraceFraction
    global_get
glb_trace_fractionflTraceFraction )
    if ( 
flTraceFraction == 1.0 )
        return

    static 
iButton iButton pev(idpev_button)
    static 
Float:flVelocity[3]

    static 
Float:_forwardFloat:right
    
static Float:vpn[3], Float:v_right[3];
    
_forward 0.0
    right 
0.0

    
new Float:flAngles[3]
    
pev(idpev_anglesflAngles)
    
engfunc(EngFunc_AngleVectorsflAnglesvpnv_right0.0);

    if ( 
iButton IN_BACK )
        
_forward -= MAX_CLIMB_SPEED;
    if ( 
iButton IN_FORWARD )
        
_forward += MAX_CLIMB_SPEED;
    if ( 
iButton IN_MOVELEFT )
        
right -= MAX_CLIMB_SPEED;
    if ( 
iButton IN_MOVERIGHT )
        
right += MAX_CLIMB_SPEED;

    new 
Float:flTracePlaneNormal[3]
    if ( 
iButton IN_JUMP )
    {
        
set_pev(idpev_movetypeMOVETYPE_WALK)
        
global_get(glb_trace_plane_normalflTracePlaneNormal)        
        
xs_vec_mul_scalar(flTracePlaneNormal270.0flVelocity)
        
set_pev(idpev_velocityflVelocity)
    }
    else
    {
        if( 
_forward || right )
        {
            static 
Float:velocity[3], Float:perp[3], Float:cross[3], Float:lateral[3], Float:tmp[3]
            static 
Float:normal

            xs_vec_mul_scalar
(vpn_forwardvelocity)
            
VectorMAvelocityrightv_rightvelocity )

            
tmp[0] = 0.0
            tmp
[1] = 0.0
            tmp
[2] = 1.0;
            
global_get(glb_trace_plane_normalflTracePlaneNormal)
            
xs_vec_crosstmpflTracePlaneNormalperp );
            
xs_vec_normalize(perpperp)

            
// decompose velocity into ladder plane
            
normal xs_vec_dotvelocityflTracePlaneNormal );
            
            
// This is the velocity into the face of the ladder
            
xs_vec_mul_scalar(flTracePlaneNormalnormalcross)

            
// This is the player's additional velocity
            
xs_vec_subvelocitycrosslateral );

            
// This turns the velocity into the face of the ladder into velocity that
            // is roughly vertically perpendicular to the face of the ladder.
            // NOTE: It IS possible to face up and move down or face down and move up
            // because the velocity is a sum of the directional velocity and the converted
            // velocity through the face of the ladder -- by design.
            
xs_vec_cross(flTracePlaneNormalperptmp)
            
VectorMAlateral, -normaltmpvelocity );
            
            if ( 
onFloor && normal )    // On ground moving away from the ladder
            
{
                
VectorMAvelocityMAX_CLIMB_SPEEDflTracePlaneNormalvelocity );
            }
            
set_pev(idpev_velocityvelocity)
        }
        else
        {
            
set_pev(idpev_velocityFloat:{0.0,0.0,0.0})
            return
        }
    }
    
gOnLadder[id] = 0
}

VectorMA(const Float:veca[3], Float:scale, const Float:vecb[3], Float:vecc[3])
{
    
vecc[0] = veca[0] + scale*vecb[0];
    
vecc[1] = veca[1] + scale*vecb[1];
    
vecc[2] = veca[2] + scale*vecb[2];

GJ! but how can we create it? like can u make something like /bm. like if we type /ladder we can make and and have move_ladder bind so we can move it.
koleos is offline
Exolent[jNr]
Veteran Member
Join Date: Feb 2007
Location: Tennessee
Old 03-09-2009 , 22:57   Re: Doing ladder
Reply With Quote #19

Try this:

Commands: (flag 'u' -- change in plugin at top)
say /ladder -- shows ladder menu
+move_ladder -- moves ladder being looked at

Requirements:
Model attached

Report any bugs you may have.
Attached Files
File Type: zip ladder_model.zip (1.6 KB, 1203 views)
File Type: sma Get Plugin or Get Source (laddermaker.sma - 2574 views - 15.8 KB)
__________________
No private work or selling mods.
Quote:
Originally Posted by xPaw View Post
I love you exolent!

Last edited by Exolent[jNr]; 03-11-2009 at 15:43.
Exolent[jNr] is offline
xPaw
Retired AMX Mod X Moderator
Join Date: Jul 2008
Old 03-10-2009 , 04:00   Re: Doing ladder
Reply With Quote #20

I love you exolent!

Maybe you could use this ladder model? its more look like ladder
Attached Files
File Type: rar ladder.rar (20.3 KB, 1059 views)
__________________

Last edited by xPaw; 03-10-2009 at 04:02.
xPaw is offline
Reply


Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -4. The time now is 15:02.


Powered by vBulletin®
Copyright ©2000 - 2024, vBulletin Solutions, Inc.
Theme made by Freecode