Jump to content

Third Person Melee Weapon Script Feedback


KeeperS Karu
 Share

Recommended Posts

Heyla and good evening!

 

So I'm not the biggest fan of first person mode, otherwise known as mouselook mode on SL. Unfortunately, every melee weapon script I've found tends to only be truly effective in mouselook mode, as it requires you to hold the left mouse button down while also pressing the directional keys to swing the weapon. In third person mode, you need that button for mouse steering, or movement will be awkward. Because I haven't been able to find a script that made the use of melee weapons in third person mode viable, I decided to mess around with a freebie melee weapon script and see if I can find something that works. And I think I did. In third person mode, instead of holding down the left mouse button in combination with the directional keys to activate the weapon swings, the player will hold down the forward button in conjunction with the left, right, and back movement buttons to swing the weapon. The left mouse button, of course, is reserved for mouse steering. It wasn't my first choice of key combos. I wanted to hold down the right mouse button instead of the left mouse button to activate the swings in third person mode, but the right mouse button isn't available (unless that's changed since last I checked?). Anyhow, I thought I'd post the modified script on here and get some feedback on how the controls feel in third person, see if there are any tweaks and suggestions you all might have to make third person melee combat a viable option for those who hate being in mouselook mode.

 

I do want to make note of the fact that I am very much a newbie in scripting. I know just enough to get by and am using what I learned in my QBASIC class over 20 years ago to organize things to the best of my ability. This is not going to be a brilliant script by any means. If you have suggestions to make this into something good enough to be passed around to others who could use it, I'm definitely all ears.

 

Thanks for reading and your feedback,

Keeper S. Karu (KeeperS Karu)

 

P.S.

Contact me in-world for a copy of the dummy melee weapon if you don't want to mess with putting something together. It's put together with my own animations and ready for playing around with.

 

The Controls:

Forward Double-Tapped --> Forward Strike

Forward + Left --> Left Strike

Forward + Left Double-Tapped --> Alternate Left Strike

Forward + Right --> Right Strike

Forward + Right Double-Tapped --> Alternate Right Strike

Forward + Back --> My dummy weapon uses a kick animation for this one; could probably use another strike animation for this

Forward + Back Double-Tapped --> Uh, I didn't realize I never took that into account; might be my first tweak to the script

 

Tweak 1:

Forward + Back --> Forward Strike

Forward + Back Double-Tapped --> Kick

 

The Script (Tweak 1):

//PREAMBLE: Module Names
//Module 1: Defining Global String Variables - Animation Names
//Module 2: Defining Global String Variables - Sound Effect Names
//Module 3: Defining Global String Variables - Bloodsplatter Object Name
//Module 4: Defining Global Integer Variables - Attack Types
//Module 5: The Double Tap Code
    //Module 5A: Defining the Double-Tap Global Vairables
    //Module 5B: Obtaining the Time the Key Was Pressed
    //Module 5C: Comparing the Time Between Key Presses
    //Module 5D: Resetting the storedTime Variable
    //Module 5E: Double Tap
//Module 6: The Sword Script
    //Module 6A: The Default State of the Sword Object When the Script Is First Executed
        //Module 6a: The Sword's Status When the Script is Reset - It Cannot Be Grabbed and                           Physically Dragged
        //Module 6b: Actions to Take When the Sword is Attached and Detached From the Avatar
        //Module 6c: If Permission Has Been Given, Take Over Keyboard Functions
        //Module 6d: Defining the Keyboard Controls
        //Module 6e: Actions to Perform When the Timer Event is Triggered
        //Module 6f: Actions to Perform if There's a Valid Target within the Predefined Sensor                        Range

//Module 1: Defining Global String Variables - Animation Names
string fwdanim = "overhead_strike_exaggerated";
string bckanim = "high_kick";
string rotrightanim = "diagonal_left_strike_exag";
string rotleftanim = "diagonal_right_strike_exag";
string straferightanim = "upward_left_strike_exag";
string strafeleftanim = "upward_right_strike_exag";
string pgdwnanim = "basic_angle_block";
string pgupanim = "backflip";

//Module 2: Defining Global String Variables - Sound Effects Names
string swdswing = "swordswing01";
string swdconnectflsh = "sword_flesh_01";
//string block swing; - If different from the other sound effects, enter them, here, as well as in the appropriate area of the code, below
string blockconnect = "sword05";
//string kick swing; - If different from the other sound effects, enter them, here, as well as in the appropriate area of the code, below
string kickconnect = "Punch04";

//Module 3: Defining Global String Variables - Bloodsplatter Object Name
string bloodsplatter = "!bloodsplatter";

//Module 4: Defining Global Integer Variables - Attack Types
integer SWORDFWD = 1;
integer SWORDRGT = 2;
integer SWORDLFT = 3;
integer BLOCK = 4;
integer KICK = 5;
integer SPECIALATK = 6;
integer strike_type;

//Module 5: The Double Tap Code

    //Module 5A: Defining the Double-Tap Global Vairables
    float strTime;
    float time;
    float storedTime;               
    float recentTime; 
    string anim = "hover";
    float interval = 1.0;

    //Module 5B: Obtaining the Time the Key Was Pressed
    getSeconds()
    {
        string timestamp    = llGetTimestamp();
        string subTime      = llGetSubString(timestamp, 19, 25);
        float wallclock     = llGetWallclock();
        strTime = (float)subTime + wallclock;
    }
    
    //Module 5C: Comparing the Time Between Key Presses              
    compareTimes(float stored, float recent)
    {
        time = recent - stored;
    }
    
    //Module 5D: Resetting the storedTime Variable
    resetStored()
    {
    storedTime = 0;
    }
    
    //Module 5E: Double Tap
    
    FStrike()
    {
        if ( time <= interval | time > interval )
        {
            llStartAnimation(fwdanim);
            llSetTimerEvent(0.75);
            strike_type = SWORDFWD;
        }
    }
    
    BStrike()
    {
        if ( time <= interval )
        {
            llStartAnimation(bckanim);
            llSetTimerEvent(0.25);
            strike_type = KICK;
        }
        else
        {
            llStartAnimation(fwdanim);
            llSetTimerEvent(0.25);
            strike_type = KICK;
        }
    }
    
    RLeft()
    {
        if ( time <= interval )
        {
            llStartAnimation(rotleftanim);
            llSetTimerEvent(0.75);
            strike_type = SWORDLFT;
        }
        else
        {
            llStartAnimation(strafeleftanim);
            llSetTimerEvent(0.75);
            strike_type = SWORDLFT;
        }
    }
    SLeft()
    {
        if ( time <= interval )
        {
            llStartAnimation(strafeleftanim);
            llSetTimerEvent(0.75);
            strike_type = SWORDLFT;
        }
        else
        {
            llStartAnimation(rotleftanim);
            llSetTimerEvent(0.75);
            strike_type = SWORDLFT;
        }
    }
    RRight()
    {
        if( time <= interval)
        {
            llStartAnimation(rotrightanim);
            llSetTimerEvent(0.75);
            strike_type = SWORDRGT;
        }
        else
        {
            llStartAnimation(straferightanim);
            llSetTimerEvent(0.75);
            strike_type = SWORDRGT;
        }
    }
    SRight()
    {
        if ( time <= interval )
        {
            llStartAnimation(straferightanim);
            llSetTimerEvent(0.75);
            strike_type = SWORDRGT;
        }
        else
        {
            llStartAnimation(rotrightanim);
            llSetTimerEvent(0.75);
            strike_type = SWORDRGT;
        }
    }

//Module 6: The Sword Script

//Module 6A: The Default State of the Sword Object When the Script Is First Executed
default
{
    //Module 6a: The Sword's Status When the Script is Reset - It Cannot Be Grabbed and Physically Dragged
    state_entry()
    {
        llSetStatus(STATUS_BLOCK_GRAB, TRUE);
    }
    
    //Module 6b: Actions to Take When the Sword is Attached and Detached From the Avatar        
    attach(key on)
    {
        if (on != NULL_KEY)
        {
            integer perm = llGetPermissions();
            
            if (perm != (PERMISSION_TAKE_CONTROLS | PERMISSION_TRIGGER_ANIMATION))
            {
                llRequestPermissions(on, PERMISSION_TAKE_CONTROLS | PERMISSION_TRIGGER_ANIMATION);
            }
            else
            {
                llTakeControls(CONTROL_ML_LBUTTON | CONTROL_LBUTTON | CONTROL_UP | CONTROL_FWD | CONTROL_BACK | CONTROL_ROT_LEFT | CONTROL_LEFT | CONTROL_RIGHT | CONTROL_ROT_RIGHT, TRUE, TRUE);
            }
            
        }
        else
        {
            llSay(0, "releasing controls");
            llReleaseControls();
        }
    }
    
    //Module 6c: If Permission Has Just Been Given, Take Over Keyboard Functions
    run_time_permissions(integer perm)
    {
        if (perm)
        {
            llTakeControls(CONTROL_ML_LBUTTON | CONTROL_LBUTTON | CONTROL_UP | CONTROL_FWD | CONTROL_BACK | CONTROL_ROT_LEFT | CONTROL_LEFT | CONTROL_RIGHT | CONTROL_ROT_RIGHT | CONTROL_DOWN, TRUE, TRUE);
        }
    }
    
    //Module 6d: Defining the Keyboard Controls   
    control(key owner, integer held, integer change)
    {
        if (held & (CONTROL_ML_LBUTTON | CONTROL_FWD))
        {
            if (change & held & CONTROL_UP)
            {
                llApplyImpulse(<0,0,3.5>,FALSE);
                llStartAnimation(pgupanim);
                llSetTimerEvent(0.25);
                strike_type = SPECIALATK;
            }
            if (change & held & CONTROL_FWD)
            {

                getSeconds();
                recentTime = strTime;                                                    
                compareTimes(storedTime, recentTime);   
                FStrike();                            
                storedTime = recentTime;
            }
            if (change & held & CONTROL_ROT_LEFT)
            {
                getSeconds();
                recentTime = strTime;                                                    
                compareTimes(storedTime, recentTime);   
                SLeft();                            
                storedTime = recentTime;
            }
            if (change & held & CONTROL_LEFT)
            {
                getSeconds();
                recentTime = strTime;                                                    
                compareTimes(storedTime, recentTime);   
                RLeft();                            
                storedTime = recentTime;
            }
            if (change & held & CONTROL_ROT_RIGHT)
            {
                getSeconds();
                recentTime = strTime;                                                    
                compareTimes(storedTime, recentTime);   
                SRight();                            
                storedTime = recentTime;
            }
            if (change & held & CONTROL_RIGHT)
            {
                getSeconds();
                recentTime = strTime;                                                    
                compareTimes(storedTime, recentTime);   
                RRight();                            
                storedTime = recentTime;
            }
             if (change & held & CONTROL_BACK)
            {
                getSeconds();
                recentTime = strTime;                                                    
                compareTimes(storedTime, recentTime);   
                BStrike();                            
                storedTime = recentTime;
            }
        }
        if (~held & change & (CONTROL_ML_LBUTTON | CONTROL_FWD))
        {
            llStopAnimation(pgdwnanim);
        }
        if (held & change & CONTROL_DOWN)
            {   
                llStartAnimation(pgdwnanim);
                llTriggerSound(swdswing, 1.0);
                llSetTimerEvent(0.01);
                strike_type = BLOCK;
                llMoveToTarget(llGetPos(), 0.25);
                llSleep(1.0);
                llStopMoveToTarget();
            }
        if (~held & change & CONTROL_DOWN)
            {   
                llStopAnimation(pgdwnanim);
            }
    }
    
    //Module 6e: Actions to Perform When the Timer Event is Triggered
    timer()
    {
        if (strike_type == SWORDFWD)
        {
            llTriggerSound(swdswing, 1.0);
            llSensor("", "", ACTIVE | AGENT, 3.0, PI_BY_TWO*0.5);
        }
        if (strike_type == SWORDRGT)
        {
            llTriggerSound(swdswing, 1.0);
            llSensor("", "", ACTIVE | AGENT, 3.0, PI_BY_TWO);
        }
        if (strike_type == SWORDLFT)
        {
            llTriggerSound(swdswing, 1.0);
            llSensor("", "", ACTIVE | AGENT, 3.0, PI_BY_TWO);
        }
        if (strike_type == BLOCK)
        {
            llSensor("", "", ACTIVE | AGENT, 2.0, PI_BY_TWO);
        }
        if (strike_type == KICK)
        {
            llTriggerSound(swdswing, 1.0);
            llSensor("", "", ACTIVE | AGENT, 3.0, PI_BY_TWO*0.5);
        }
        if (strike_type == SPECIALATK)
        {
            llTriggerSound(swdswing, 1.0);
            llSensor("", "", ACTIVE | AGENT, 3.0, PI_BY_TWO*0.5);
        }
        llSetTimerEvent(0.0);
    }
    
    //Module 6f: Actions to Perform if There's a Valid Target within the Predefined Sensor Range
    sensor(integer tnum)
    {
        vector dir = llDetectedPos(0) - llGetPos();
        dir.z = 0.0;
        dir = llVecNorm(dir);
        rotation rot = llGetRot();
        
        if (strike_type == SWORDFWD)
        {
            llTriggerSound(swdconnectflsh, 1.0);
            llRezObject(bloodsplatter,llDetectedPos(0),<0,0,0>,ZERO_ROTATION,TRUE);
            dir += llRot2Up(rot);
            dir *= 200.0;
            llPushObject(llDetectedKey(0), dir, ZERO_VECTOR, FALSE);
        }
        else if (strike_type == SWORDRGT)
        {
            llTriggerSound(swdconnectflsh, 1.0);
            llRezObject(bloodsplatter,llDetectedPos(0),<0,0,0>,ZERO_ROTATION,TRUE);
            dir += dir;
            dir *= 100.0;
            llPushObject(llDetectedKey(0), dir, ZERO_VECTOR, FALSE);
        }
        else if (strike_type == SWORDLFT)
        {
            llTriggerSound(swdconnectflsh, 1.0);
            llRezObject(bloodsplatter,llDetectedPos(0),<0,0,0>,ZERO_ROTATION,TRUE);
            dir -= llRot2Left(rot);
            dir *= 100.0;
            llPushObject(llDetectedKey(0), dir, ZERO_VECTOR, FALSE);
        }
        else if (strike_type == KICK)
        {
            llTriggerSound(kickconnect, 1.0);
            dir += dir;
            dir *= 100.0;
            llPushObject(llDetectedKey(0), dir, ZERO_VECTOR, FALSE);
        }
        else if (strike_type == BLOCK)
        {
            llTriggerSound(blockconnect, 1.0);
        }
        else if (strike_type == SPECIALATK)
        {
            llTriggerSound(swdswing, 1.0);
            llPushObject(llDetectedKey(0), <0,0,150>, ZERO_VECTOR, FALSE);
        }
        strike_type= 0;
    }
}

 

The Script:

//PREAMBLE: Module Names
//Module 1: Defining Global String Variables - Animation Names
//Module 2: Defining Global String Variables - Sound Effect Names
//Module 3: Defining Global String Variables - Bloodsplatter Object Name
//Module 4: Defining Global Integer Variables - Attack Types
//Module 5: The Double Tap Code
    //Module 5A: Defining the Double-Tap Global Vairables
    //Module 5B: Obtaining the Time the Key Was Pressed
    //Module 5C: Comparing the Time Between Key Presses
    //Module 5D: Resetting the storedTime Variable
    //Module 5E: Double Tap
//Module 6: The Sword Script
    //Module 6A: The Default State of the Sword Object When the Script Is First Executed
        //Module 6a: The Sword's Status When the Script is Reset - It Cannot Be Grabbed and Physically Dragged
        //Module 6b: Actions to Take When the Sword is Attached and Detached From the Avatar
        //Module 6c: If Permission Has Been Given, Take Over Keyboard Functions
        //Module 6d: Defining the Keyboard Controls
        //Module 6e: Actions to Perform When the Timer Event is Triggered
        //Module 6f: Actions to Perform if There's a Valid Target within the Predefined Sensor Range

//Module 1: Defining Global String Variables - Animation Names
string fwdanim = "overhead_strike_exaggerated";
string bckanim = "high_kick";
string rotrightanim = "diagonal_left_strike_exag";
string rotleftanim = "diagonal_right_strike_exag";
string straferightanim = "upward_left_strike_exag";
string strafeleftanim = "upward_right_strike_exag";
string pgdwnanim = "basic_angle_block";
string pgupanim = "backflip";

//Module 2: Defining Global String Variables - Sound Effects Names
string swdswing = "swordswing01";
string swdconnectflsh = "sword_flesh_01";
//string block swing; - If different from the other sound effects, enter them, here, as well as in the appropriate area of the code, below
string blockconnect = "sword05";
//string kick swing; - If different from the other sound effects, enter them, here, as well as in the appropriate area of the code, below
string kickconnect = "Punch04";

//Module 3: Defining Global String Variables - Bloodsplatter Object Name
string bloodsplatter = "!bloodsplatter";

//Module 4: Defining Global Integer Variables - Attack Types
integer SWORDFWD = 1;
integer SWORDRGT = 2;
integer SWORDLFT = 3;
integer BLOCK = 4;
integer KICK = 5;
integer SPECIALATK = 6;
integer strike_type;

//Module 5: The Double Tap Code

    //Module 5A: Defining the Double-Tap Global Vairables
    float strTime;
    float time;
    float storedTime;               
    float recentTime; 
    string anim = "hover";
    float interval = 1.0;

    //Module 5B: Obtaining the Time the Key Was Pressed
    getSeconds()
    {
        string timestamp    = llGetTimestamp();
        string subTime      = llGetSubString(timestamp, 19, 25);
        float wallclock     = llGetWallclock();
        strTime = (float)subTime + wallclock;
    }
    
    //Module 5C: Comparing the Time Between Key Presses              
    compareTimes(float stored, float recent)
    {
        time = recent - stored;
    }
    
    //Module 5D: Resetting the storedTime Variable
    resetStored()
    {
    storedTime = 0;
    }
    
    //Module 5E: Double Tap
    
    FStrike()
    {
        if ( time <= interval | time > interval )
        {
            llStartAnimation(fwdanim);
            llSetTimerEvent(0.75);
            strike_type = SWORDFWD;
        }
    }
    
    RLeft()
    {
        if ( time <= interval )
        {
            llStartAnimation(rotleftanim);
            llSetTimerEvent(0.75);
            strike_type = SWORDLFT;
        }
        else
        {
            llStartAnimation(strafeleftanim);
            llSetTimerEvent(0.75);
            strike_type = SWORDLFT;
        }
    }
    SLeft()
    {
        if ( time <= interval )
        {
            llStartAnimation(strafeleftanim);
            llSetTimerEvent(0.75);
            strike_type = SWORDLFT;
        }
        else
        {
            llStartAnimation(rotleftanim);
            llSetTimerEvent(0.75);
            strike_type = SWORDLFT;
        }
    }
    RRight()
    {
        if( time <= interval)
        {
            llStartAnimation(rotrightanim);
            llSetTimerEvent(0.75);
            strike_type = SWORDRGT;
        }
        else
        {
            llStartAnimation(straferightanim);
            llSetTimerEvent(0.75);
            strike_type = SWORDRGT;
        }
    }
    SRight()
    {
        if ( time <= interval )
        {
            llStartAnimation(straferightanim);
            llSetTimerEvent(0.75);
            strike_type = SWORDRGT;
        }
        else
        {
            llStartAnimation(rotrightanim);
            llSetTimerEvent(0.75);
            strike_type = SWORDRGT;
        }
    }

//Module 6: The Sword Script

//Module 6A: The Default State of the Sword Object When the Script Is First Executed
default
{
    //Module 6a: The Sword's Status When the Script is Reset - It Cannot Be Grabbed and Physically Dragged
    state_entry()
    {
        llSetStatus(STATUS_BLOCK_GRAB, TRUE);
    }
    
    //Module 6b: Actions to Take When the Sword is Attached and Detached From the Avatar        
    attach(key on)
    {
        if (on != NULL_KEY)
        {
            integer perm = llGetPermissions();
            
            if (perm != (PERMISSION_TAKE_CONTROLS | PERMISSION_TRIGGER_ANIMATION))
            {
                llRequestPermissions(on, PERMISSION_TAKE_CONTROLS | PERMISSION_TRIGGER_ANIMATION);
            }
            else
            {
                llTakeControls(CONTROL_ML_LBUTTON | CONTROL_LBUTTON | CONTROL_UP | CONTROL_FWD | CONTROL_BACK | CONTROL_ROT_LEFT | CONTROL_LEFT | CONTROL_RIGHT | CONTROL_ROT_RIGHT, TRUE, TRUE);
            }
            
        }
        else
        {
            llSay(0, "releasing controls");
            llReleaseControls();
        }
    }
    
    //Module 6c: If Permission Has Just Been Given, Take Over Keyboard Functions
    run_time_permissions(integer perm)
    {
        if (perm)
        {
            llTakeControls(CONTROL_ML_LBUTTON | CONTROL_LBUTTON | CONTROL_UP | CONTROL_FWD | CONTROL_BACK | CONTROL_ROT_LEFT | CONTROL_LEFT | CONTROL_RIGHT | CONTROL_ROT_RIGHT | CONTROL_DOWN, TRUE, TRUE);
        }
    }
    
    //Module 6d: Defining the Keyboard Controls   
    control(key owner, integer held, integer change)
    {
        if (held & (CONTROL_ML_LBUTTON | CONTROL_FWD))
        {
            if (change & held & CONTROL_UP)
            {
                llApplyImpulse(<0,0,3.5>,FALSE);
                llStartAnimation(pgupanim);
                llSetTimerEvent(0.25);
                strike_type = SPECIALATK;
            }
            if (change & held & CONTROL_FWD)
            {

                getSeconds();
                recentTime = strTime;                                                    
                compareTimes(storedTime, recentTime);   
                FStrike();                            
                storedTime = recentTime;
            }
            if (change & held & CONTROL_ROT_LEFT)
            {
                getSeconds();
                recentTime = strTime;                                                    
                compareTimes(storedTime, recentTime);   
                SLeft();                            
                storedTime = recentTime;
            }
            if (change & held & CONTROL_LEFT)
            {
                getSeconds();
                recentTime = strTime;                                                    
                compareTimes(storedTime, recentTime);   
                RLeft();                            
                storedTime = recentTime;
            }
            if (change & held & CONTROL_ROT_RIGHT)
            {
                getSeconds();
                recentTime = strTime;                                                    
                compareTimes(storedTime, recentTime);   
                SRight();                            
                storedTime = recentTime;
            }
            if (change & held & CONTROL_RIGHT)
            {
                getSeconds();
                recentTime = strTime;                                                    
                compareTimes(storedTime, recentTime);   
                RRight();                            
                storedTime = recentTime;
            }
             if (change & held & CONTROL_BACK)
            {
                llStartAnimation(bckanim);
                llSetTimerEvent(0.25);
                strike_type = KICK;
            }
        }
        if (~held & change & (CONTROL_ML_LBUTTON | CONTROL_FWD))
        {
            llStopAnimation(pgdwnanim);
        }
        if (held & change & CONTROL_DOWN)
            {   
                llStartAnimation(pgdwnanim);
                llTriggerSound(swdswing, 1.0);
                llSetTimerEvent(0.01);
                strike_type = BLOCK;
                llMoveToTarget(llGetPos(), 0.25);
                llSleep(1.0);
                llStopMoveToTarget();
            }
        if (~held & change & CONTROL_DOWN)
            {   
                llStopAnimation(pgdwnanim);
            }
    }
    
    //Module 6e: Actions to Perform When the Timer Event is Triggered
    timer()
    {
        if (strike_type == SWORDFWD)
        {
            llTriggerSound(swdswing, 1.0);
            llSensor("", "", ACTIVE | AGENT, 3.0, PI_BY_TWO*0.5);
        }
        if (strike_type == SWORDRGT)
        {
            llTriggerSound(swdswing, 1.0);
            llSensor("", "", ACTIVE | AGENT, 3.0, PI_BY_TWO);
        }
        if (strike_type == SWORDLFT)
        {
            llTriggerSound(swdswing, 1.0);
            llSensor("", "", ACTIVE | AGENT, 3.0, PI_BY_TWO);
        }
        if (strike_type == BLOCK)
        {
            llSensor("", "", ACTIVE | AGENT, 2.0, PI_BY_TWO);
        }
        if (strike_type == KICK)
        {
            llTriggerSound(swdswing, 1.0);
            llSensor("", "", ACTIVE | AGENT, 3.0, PI_BY_TWO*0.5);
        }
        if (strike_type == SPECIALATK)
        {
            llTriggerSound(swdswing, 1.0);
            llSensor("", "", ACTIVE | AGENT, 3.0, PI_BY_TWO*0.5);
        }
        llSetTimerEvent(0.0);
    }
    
    //Module 6f: Actions to Perform if There's a Valid Target within the Predefined Sensor Range
    sensor(integer tnum)
    {
        vector dir = llDetectedPos(0) - llGetPos();
        dir.z = 0.0;
        dir = llVecNorm(dir);
        rotation rot = llGetRot();
        
        if (strike_type == SWORDFWD)
        {
            llTriggerSound(swdconnectflsh, 1.0);
            llRezObject(bloodsplatter,llDetectedPos(0),<0,0,0>,ZERO_ROTATION,TRUE);
            dir += llRot2Up(rot);
            dir *= 200.0;
            llPushObject(llDetectedKey(0), dir, ZERO_VECTOR, FALSE);
        }
        else if (strike_type == SWORDRGT)
        {
            llTriggerSound(swdconnectflsh, 1.0);
            llRezObject(bloodsplatter,llDetectedPos(0),<0,0,0>,ZERO_ROTATION,TRUE);
            dir += dir;
            dir *= 100.0;
            llPushObject(llDetectedKey(0), dir, ZERO_VECTOR, FALSE);
        }
        else if (strike_type == SWORDLFT)
        {
            llTriggerSound(swdconnectflsh, 1.0);
            llRezObject(bloodsplatter,llDetectedPos(0),<0,0,0>,ZERO_ROTATION,TRUE);
            dir -= llRot2Left(rot);
            dir *= 100.0;
            llPushObject(llDetectedKey(0), dir, ZERO_VECTOR, FALSE);
        }
        else if (strike_type == KICK)
        {
            llTriggerSound(kickconnect, 1.0);
            dir += dir;
            dir *= 100.0;
            llPushObject(llDetectedKey(0), dir, ZERO_VECTOR, FALSE);
        }
        else if (strike_type == BLOCK)
        {
            llTriggerSound(blockconnect, 1.0);
        }
        else if (strike_type == SPECIALATK)
        {
            llTriggerSound(swdswing, 1.0);
            llPushObject(llDetectedKey(0), <0,0,150>, ZERO_VECTOR, FALSE);
        }
        strike_type= 0;
    }
}

 

Edited by KeeperS Karu
Link to comment
Share on other sites

Heyla!

 

I've tweaked the script again. Tweak 2 works in conjunction with the draw/sheathe scripts I've made to go with the main melee weapon script. In it, if the user draws their weapon, their weapon becomes active and ready for use. If the user sheathes their weapon, the weapon becomes inactive, releasing controls so the user doesn't accidentally use their weapon when they expect it to be inactive. (I wish I could say that I was brilliant and came up with the code, myself. Instead, it was code I learned while studying the Myriad Lite script-set, a free and open-source combat system. Credit where credit is due.)

 

I'm also including in this post the draw/sheathe scripts for examination and feedback. I am especially hoping for feedback on how to better go about making the sword and hilt visible and invisible when they use PBR materials. Right now, as it stands, it's not very flexible. To become invisible, it removes the PBR material, and to become visible, it adds the specific material back to the weapon. I'm hoping there's an alpha function for PBR materials that I just haven't seen yet.

 

Thanks for reading, and I look forward to your feedback and advice!

Keeper S. Karu (KeeperS Karu)

 

The Melee Weapon Script, Tweak #2:

//PREAMBLE: Module Names
//Module 1: Defining Global String Variables - Animation Names
//Module 2: Defining Global String Variables - Sound Effect Names
//Module 3: Defining Global String Variables - Bloodsplatter Object Name
//Module 4: Defining Global Variables - MISC
     //Module 4A: Attack Types
     //Module 4B: Weapon Safety Variables
//Module 5: The Safety Functions
    //Module 5A: Safety On
    //Module 5B: Safety Off
//Module 6: The Double Tap Code
    //Module 6A: Defining the Double-Tap Global Vairables
    //Module 6B: Obtaining the Time the Key Was Pressed
    //Module 6C: Comparing the Time Between Key Presses
    //Module 6D: Resetting the storedTime Variable
    //Module 6E: Double Tap
//Module 7: The Sword Script
    //Module 7A: The Default State of the Sword Object When the Script Is First Executed
        //Module 7a: The Sword's Status When the Script is Reset - It Cannot Be Grabbed and Physically Dragged
        //Module 7b: Actions to Take When the Sword is Attached and Detached From the Avatar
        //Module 7c: If Permission Has Been Given, Take Over Keyboard Functions
        //Module 7d: Is The Safety On?
        //Module 7e: Defining the Keyboard Controls
        //Module 7f: Actions to Perform When the Timer Event is Triggered
        //Module 7g: Actions to Perform if There's a Valid Target within the Predefined Sensor Range

//Module 1: Defining Global String Variables - Animation Names
string fwdanim = "overhead_strike_exaggerated";
string bckanim = "high_kick";
string rotrightanim = "diagonal_left_strike_exag";
string rotleftanim = "diagonal_right_strike_exag";
string straferightanim = "upward_left_strike_exag";
string strafeleftanim = "upward_right_strike_exag";
string pgdwnanim = "basic_angle_block";
string pgupanim = "backflip";

//Module 2: Defining Global String Variables - Sound Effects Names
string swdswing = "swordswing01";
string swdconnectflsh = "sword_flesh_01";
//string block swing; - If different from the other sound effects, enter them, here, as well as in the appropriate area of the code, below
string blockconnect = "sword05";
//string kick swing; - If different from the other sound effects, enter them, here, as well as in the appropriate area of the code, below
string kickconnect = "Punch04";

//Module 3: Defining Global String Variables - Bloodsplatter Object Name
string bloodsplatter = "!bloodsplatter";

//Module 4: Defining Global Variables - MISC

    //Module 4A: Attack Types
    integer SWORDFWD = 1;
    integer SWORDRGT = 2;
    integer SWORDLFT = 3;
    integer BLOCK = 4;
    integer KICK = 5;
    integer SPECIALATK = 6;
    integer strike_type;
    
    //4Module 4B: Weapon Safety Variables
    
    string g_message;
    integer listen_handle;
    integer SAFETY_ON = TRUE;
    
//Module 5: The Safety Functions

    //Module 5A: Safety On
    SAFETYON()
    {
        SAFETY_ON = TRUE; // switch the safety on
        llSay(0, "releasing controls");
        llReleaseControls();
    }

    //Module 5B: Safety Off
    SAFETYOFF()
    {
        SAFETY_ON = FALSE; // switch the safety off
        llRequestPermissions(llGetOwner(),PERMISSION_TAKE_CONTROLS|PERMISSION_TRIGGER_ANIMATION); // request permissions
    }

//Module 6: The Double Tap Code

    //Module 6A: Defining the Double-Tap Global Vairables
    float strTime;
    float time;
    float storedTime;               
    float recentTime; 
    string anim = "hover";
    float interval = 1.0;

    //Module 6B: Obtaining the Time the Key Was Pressed
    getSeconds()
    {
        string timestamp    = llGetTimestamp();
        string subTime      = llGetSubString(timestamp, 19, 25);
        float wallclock     = llGetWallclock();
        strTime = (float)subTime + wallclock;
    }
    
    //Module 6C: Comparing the Time Between Key Presses              
    compareTimes(float stored, float recent)
    {
        time = recent - stored;
    }
    
    //Module 6D: Resetting the storedTime Variable
    resetStored()
    {
    storedTime = 0;
    }
    
    //Module 6E: Double Tap
    
    FStrike()
    {
        if ( time <= interval | time > interval )
        {
            llStartAnimation(fwdanim);
            llSetTimerEvent(0.75);
            strike_type = SWORDFWD;
        }
    }
    
    BStrike()
    {
        if ( time <= interval )
        {
            llStartAnimation(bckanim);
            llSetTimerEvent(0.25);
            strike_type = KICK;
        }
        else
        {
            llStartAnimation(fwdanim);
            llSetTimerEvent(0.25);
            strike_type = KICK;
        }
    }
    
    RLeft()
    {
        if ( time <= interval )
        {
            llStartAnimation(rotleftanim);
            llSetTimerEvent(0.75);
            strike_type = SWORDLFT;
        }
        else
        {
            llStartAnimation(strafeleftanim);
            llSetTimerEvent(0.75);
            strike_type = SWORDLFT;
        }
    }
    SLeft()
    {
        if ( time <= interval )
        {
            llStartAnimation(strafeleftanim);
            llSetTimerEvent(0.75);
            strike_type = SWORDLFT;
        }
        else
        {
            llStartAnimation(rotleftanim);
            llSetTimerEvent(0.75);
            strike_type = SWORDLFT;
        }
    }
    RRight()
    {
        if( time <= interval)
        {
            llStartAnimation(rotrightanim);
            llSetTimerEvent(0.75);
            strike_type = SWORDRGT;
        }
        else
        {
            llStartAnimation(straferightanim);
            llSetTimerEvent(0.75);
            strike_type = SWORDRGT;
        }
    }
    SRight()
    {
        if ( time <= interval )
        {
            llStartAnimation(straferightanim);
            llSetTimerEvent(0.75);
            strike_type = SWORDRGT;
        }
        else
        {
            llStartAnimation(rotrightanim);
            llSetTimerEvent(0.75);
            strike_type = SWORDRGT;
        }
    }

//Module 7: The Sword Script

//Module 7A: The Default State of the Sword Object When the Script Is First Executed
default
{
    //Module 7a: The Sword's Status When the Script is Reset - It Cannot Be Grabbed and Physically Dragged
    state_entry()
    {
        llSetStatus(STATUS_BLOCK_GRAB, TRUE);
        llListenRemove(listen_handle);
        listen_handle = llListen(5, "", llGetOwner(), "");
    }
    
    //Module 7b: Actions to Take When the Sword is Attached and Detached From the Avatar        
    attach(key on)
    {
        if (on != NULL_KEY)
        {
            integer perm = llGetPermissions();
            
            if (perm != (PERMISSION_TAKE_CONTROLS | PERMISSION_TRIGGER_ANIMATION))
            {
                llRequestPermissions(on, PERMISSION_TAKE_CONTROLS | PERMISSION_TRIGGER_ANIMATION);
            }
            else
            {
                llTakeControls(CONTROL_ML_LBUTTON | CONTROL_LBUTTON | CONTROL_UP | CONTROL_FWD | CONTROL_BACK | CONTROL_ROT_LEFT | CONTROL_LEFT | CONTROL_RIGHT | CONTROL_ROT_RIGHT, TRUE, TRUE);
            }
            
        }
        else
        {
            llSay(0, "releasing controls");
            llReleaseControls();
        }
    }
    
    //Module 7c: If Permission Has Just Been Given, Take Over Keyboard Functions
    run_time_permissions(integer perm)
    {
        if (perm)
        {
            llTakeControls(CONTROL_ML_LBUTTON | CONTROL_LBUTTON | CONTROL_UP | CONTROL_FWD | CONTROL_BACK | CONTROL_ROT_LEFT | CONTROL_LEFT | CONTROL_RIGHT | CONTROL_ROT_RIGHT | CONTROL_DOWN, TRUE, TRUE);
        }
    }
    
    //Module 7d: Is The Safety On?
    
    listen(integer channel, string name, key id, string message)
        {   
            g_message = llToLower(message);

            if( g_message == "hdraw" )
            {
                SAFETYOFF();
            }
            if( g_message == "sdraw" )
            {
                SAFETYOFF();
            }
            else if(g_message == "hsheathe") 
            {
                SAFETYON();
            }
            else if(g_message == "ssheathe") 
            {
                SAFETYON();
            }
        }
    
    //Module 7e: Defining the Keyboard Controls   
    control(key owner, integer held, integer change)
    {

            if (held & (CONTROL_ML_LBUTTON | CONTROL_FWD))
            {
                if (change & held & CONTROL_UP)
                {
                    llApplyImpulse(<0,0,3.5>,FALSE);
                    llStartAnimation(pgupanim);
                    llSetTimerEvent(0.25);
                    strike_type = SPECIALATK;
                }
                if (change & held & CONTROL_FWD)
                {
    
                    getSeconds();
                    recentTime = strTime;                                                    
                    compareTimes(storedTime, recentTime);   
                    FStrike();                            
                    storedTime = recentTime;
                }
                if (change & held & CONTROL_ROT_LEFT)
                {
                    getSeconds();
                    recentTime = strTime;                                                    
                    compareTimes(storedTime, recentTime);   
                    SLeft();                            
                    storedTime = recentTime;
                }
                if (change & held & CONTROL_LEFT)
                {
                    getSeconds();
                    recentTime = strTime;                                                    
                    compareTimes(storedTime, recentTime);   
                    RLeft();                            
                    storedTime = recentTime;
                }
                if (change & held & CONTROL_ROT_RIGHT)
                {
                    getSeconds();
                    recentTime = strTime;                                                    
                    compareTimes(storedTime, recentTime);   
                    SRight();                            
                    storedTime = recentTime;
                }
                if (change & held & CONTROL_RIGHT)
                {
                    getSeconds();
                    recentTime = strTime;                                                    
                    compareTimes(storedTime, recentTime);   
                    RRight();                            
                    storedTime = recentTime;
                }
                 if (change & held & CONTROL_BACK)
                {
                    getSeconds();
                    recentTime = strTime;                                                    
                    compareTimes(storedTime, recentTime);   
                    BStrike();                            
                    storedTime = recentTime;
                }
            }
            if (~held & change & (CONTROL_ML_LBUTTON | CONTROL_FWD))
            {
                llStopAnimation(pgdwnanim);
            }
            if (held & change & CONTROL_DOWN)
                {   
                    llStartAnimation(pgdwnanim);
                    llTriggerSound(swdswing, 1.0);
                    llSetTimerEvent(0.01);
                    strike_type = BLOCK;
                    llMoveToTarget(llGetPos(), 0.25);
                    llSleep(1.0);
                    llStopMoveToTarget();
                }
            if (~held & change & CONTROL_DOWN)
                {   
                    llStopAnimation(pgdwnanim);
                }

    }
    
    //Module 7f: Actions to Perform When the Timer Event is Triggered
    timer()
    {
        if (strike_type == SWORDFWD)
        {
            llTriggerSound(swdswing, 1.0);
            llSensor("", "", ACTIVE | AGENT, 3.0, PI_BY_TWO*0.5);
        }
        if (strike_type == SWORDRGT)
        {
            llTriggerSound(swdswing, 1.0);
            llSensor("", "", ACTIVE | AGENT, 3.0, PI_BY_TWO);
        }
        if (strike_type == SWORDLFT)
        {
            llTriggerSound(swdswing, 1.0);
            llSensor("", "", ACTIVE | AGENT, 3.0, PI_BY_TWO);
        }
        if (strike_type == BLOCK)
        {
            llSensor("", "", ACTIVE | AGENT, 2.0, PI_BY_TWO);
        }
        if (strike_type == KICK)
        {
            llTriggerSound(swdswing, 1.0);
            llSensor("", "", ACTIVE | AGENT, 3.0, PI_BY_TWO*0.5);
        }
        if (strike_type == SPECIALATK)
        {
            llTriggerSound(swdswing, 1.0);
            llSensor("", "", ACTIVE | AGENT, 3.0, PI_BY_TWO*0.5);
        }
        llSetTimerEvent(0.0);
    }
    
    //Module 7g: Actions to Perform if There's a Valid Target within the Predefined Sensor Range
    sensor(integer tnum)
    {
        vector dir = llDetectedPos(0) - llGetPos();
        dir.z = 0.0;
        dir = llVecNorm(dir);
        rotation rot = llGetRot();
        
        if (strike_type == SWORDFWD)
        {
            llTriggerSound(swdconnectflsh, 1.0);
            llRezObject(bloodsplatter,llDetectedPos(0),<0,0,0>,ZERO_ROTATION,TRUE);
            dir += llRot2Up(rot);
            dir *= 200.0;
            llPushObject(llDetectedKey(0), dir, ZERO_VECTOR, FALSE);
        }
        else if (strike_type == SWORDRGT)
        {
            llTriggerSound(swdconnectflsh, 1.0);
            llRezObject(bloodsplatter,llDetectedPos(0),<0,0,0>,ZERO_ROTATION,TRUE);
            dir += dir;
            dir *= 100.0;
            llPushObject(llDetectedKey(0), dir, ZERO_VECTOR, FALSE);
        }
        else if (strike_type == SWORDLFT)
        {
            llTriggerSound(swdconnectflsh, 1.0);
            llRezObject(bloodsplatter,llDetectedPos(0),<0,0,0>,ZERO_ROTATION,TRUE);
            dir -= llRot2Left(rot);
            dir *= 100.0;
            llPushObject(llDetectedKey(0), dir, ZERO_VECTOR, FALSE);
        }
        else if (strike_type == KICK)
        {
            llTriggerSound(kickconnect, 1.0);
            dir += dir;
            dir *= 100.0;
            llPushObject(llDetectedKey(0), dir, ZERO_VECTOR, FALSE);
        }
        else if (strike_type == BLOCK)
        {
            llTriggerSound(blockconnect, 1.0);
        }
        else if (strike_type == SPECIALATK)
        {
            llTriggerSound(swdswing, 1.0);
            llPushObject(llDetectedKey(0), <0,0,150>, ZERO_VECTOR, FALSE);
        }
        strike_type= 0;
    }
}

 

The Draw/Sheathe Script for the weapon:

//PREAMBLE: Module Names
//Module 1: Defining Global String Varaibles - Animation Names
//Module 2: Defining Global String Variables - Sound Effects Names
//Module 3: Defining Global String Variables - String Parameters
//Module 4: Defining Global Integer Variable - Integer Parameters
//Module 5: The Draw/Sheathe Script
            //Module 5A: Reset the Script Whenever the Object is Rezzed
            //Module 5B: Obtain Permission to Animate the Avatar & Listen for Commands From the Avatar
            //Module 5C: If Permission Has Been Given, Then Letthe Following Conditions Be True
            //Module 5D: Actions to Take When the Avatar Delivers the Draw and Sheathe Commands Via Chat
            //Module 5E: Trigger the Sword Draw Sound Effect and Render the Sword Visible or Invisible, As Appropriate


//Module 1: Defining Global String Varaibles - Animation Names
string hdraw = "hip_draw";
string hsheathe = "hip_sheathe";
string sdraw = "Draw - .7 Seconds";
string ssheathe = "Sheathe - 0.77 Sec";
string stance = "basic_stance";

//Module 2: Defining Global String Variables - Sound Effects Names
string sworddraw = "swordraw";

//Module 3: Defining Global String Variables - String Parameters
string g_message;

//Module 4: Defining Global Integer Variable - Integer Parameters
integer listen_handle;
integer permissions;

//Module 5: The Draw/Sheathe Script
default
{
    //Module 5A: Reset the Script Whenever the Object is Rezzed
    on_rez(integer start_param)
    {
        llResetScript();
    }
    
    //Module 5B: Obtain Permission to Animate the Avatar & Listen for Commands From the Avatar
    state_entry()
    {
        if( llGetAttached() );
        {
            llRequestPermissions(llGetOwner(), PERMISSION_TRIGGER_ANIMATION);
        }        
        llListenRemove(listen_handle);
        listen_handle = llListen(5, "", llGetOwner(), "");
    }
    
    //Module 5C: If Permission Has Been Given, Then Let The Following Conditions Be True
    run_time_permissions(integer perms)
        {
            if( perms & PERMISSION_TRIGGER_ANIMATION )
            {
                permissions = TRUE;
            }
        }
    
    //Module 5D: Actions to Take When the Avatar Delivers the Draw and Sheathe Commands Via Chat
    listen(integer channel, string name, key id, string message)
        {   
            g_message = llToLower(message);

            if( g_message == "hdraw" )
            {
                if(permissions)
                {
                    llStartAnimation(hdraw);
                    llStartAnimation(stance);
                    llSetTimerEvent(0.25);
                }
            }
            if( g_message == "sdraw" )
            {
                if(permissions)
                {
                    llStartAnimation(sdraw);
                    llStartAnimation(stance);
                    llSetTimerEvent(0.25);
                }
            }
            else if(g_message == "hsheathe") 
            {
                if(permissions)
                {
                    llStartAnimation(hsheathe);
                    llStopAnimation(stance);
                    llSetTimerEvent(0.75);
                }
            }
            else if(g_message == "ssheathe") 
            {
                if(permissions)
                {
                    llStartAnimation(ssheathe);
                    llStopAnimation(stance);
                    llSetTimerEvent(0.75);
                }
            }
        }
        
    //Module 5E: Trigger the Sword Draw Sound Effect and Render the Sword Visible or Invisible, As Appropriate
    timer()
    {   
        if( g_message == "hdraw")
        {
            if( permissions )
            {
                llTriggerSound(sworddraw, 1.0);
                llSetLinkAlpha(LINK_SET,1.0, ALL_SIDES);
                llSetPrimitiveParams([PRIM_RENDER_MATERIAL, ALL_SIDES, "Texture UUID Here"]);
            }
        }
        if( g_message == "sdraw")
        {
            if( permissions )
            {
                llTriggerSound(sworddraw, 1.0);
                llSetLinkAlpha(LINK_SET,1.0, ALL_SIDES);
                llSetPrimitiveParams([PRIM_RENDER_MATERIAL, ALL_SIDES, "Texture UUID Here"]);
            }
        }
        else if( g_message == "hsheathe")
        {
            if( permissions )
                {
                    llTriggerSound(sworddraw, 1.0);
                    llSetLinkAlpha(LINK_SET,0, ALL_SIDES);
                    llSetPrimitiveParams([PRIM_RENDER_MATERIAL, ALL_SIDES, NULL_KEY]);
                }
        }
        else if( g_message == "ssheathe")
        {
            if( permissions )
                {
                    llTriggerSound(sworddraw, 1.0);
                    llSetLinkAlpha(LINK_SET,0, ALL_SIDES);
                    llSetPrimitiveParams([PRIM_RENDER_MATERIAL, ALL_SIDES, NULL_KEY]);
                }
        }
        
        llSetTimerEvent(0);
    }
    
}

 

The Draw/Sheathe Script for the Sheath:

//PREAMBLE: Module Names
//Module 1: Defining Global String Variables - String Parameters
//Module 2: Defining Global Integer Variable - Integer Parameters
//Module 3: The Draw/Sheathe Script
            //Module 3A: Reset the Script Whenever the Object is Rezzed
            //Module 3B: Listen for Commands From the Avatar
            //Module 3C: Actions to Take When the Avatar Delivers the Draw and Sheathe Commands Via Chat
            //Module 3D: Trigger the Sword Draw Sound Effect and Render the Sword Visible or Invisible, As Appropriate


//Module 1: Defining Global String Variables - String Parameters
string g_message;

//Module 2: Defining Global Integer Variable - Integer Parameters
integer listen_handle;

//Module 3: The Draw/Sheathe Script
default
{
    //Module 3A: Reset the Script Whenever the Object is Rezzed
    on_rez(integer start_param)
    {
        llResetScript();
    }
    
    //Module 3B: Listen for Commands From the Avatar
    state_entry()
    {
        llListenRemove(listen_handle);
        listen_handle = llListen(5, "", llGetOwner(), "");
    }
    
    //Module 3C: Actions to Take When the Avatar Delivers the Draw and Sheathe Commands Via Chat  
    listen(integer channel, string name, key id, string message)
        {
            
            g_message = llToLower(message);

            if(g_message == "hdraw")
            {
                llSetTimerEvent(0.25);
            }
            if(g_message == "sdraw")
            {
                llSetTimerEvent(0.25);
            }
            else if(g_message == "hsheathe") 
            {
                llSetTimerEvent(0.75);
            }
            else if(g_message == "ssheathe") 
            {
                llSetTimerEvent(0.75);
            }
        }
    
    //Module 3D: Render the Sword Hilt Visible or Invisible, As Appropriate
    timer()
    {   
    
        if( g_message == "hdraw" )
        {
            llSetAlpha(0.0, ALL_SIDES);
            llSetPrimitiveParams([PRIM_RENDER_MATERIAL, ALL_SIDES, NULL_KEY]);
            
        }
        if( g_message == "sdraw" )
        {
            llSetAlpha(0.0, ALL_SIDES);
            llSetPrimitiveParams([PRIM_RENDER_MATERIAL, ALL_SIDES, NULL_KEY]);
            
        }
        else if( g_message == "hsheathe" )
        {
            llSetAlpha(1.0, ALL_SIDES);
            llSetPrimitiveParams([PRIM_RENDER_MATERIAL, 1, "Texture UUID Here"]);
            llSetPrimitiveParams([PRIM_RENDER_MATERIAL, 2, "Texture UUID Here"]);
            llSetPrimitiveParams([PRIM_RENDER_MATERIAL, 3, "Texture UUID Here"]);
            llSetPrimitiveParams([PRIM_RENDER_MATERIAL, 4, "Texture UUID Here"]);
        }
        else if( g_message == "ssheathe" )
        {
            llSetAlpha(1.0, ALL_SIDES);
            llSetPrimitiveParams([PRIM_RENDER_MATERIAL, 1, "Texture UUID Here"]);
            llSetPrimitiveParams([PRIM_RENDER_MATERIAL, 2, "Texture UUID Here"]);
            llSetPrimitiveParams([PRIM_RENDER_MATERIAL, 3, "Texture UUID Here"]);
            llSetPrimitiveParams([PRIM_RENDER_MATERIAL, 4, "Texture UUID Here"]);
        }
        
        llSetTimerEvent(0);
    }
    
}

 

Link to comment
Share on other sites

I've never had to get that involved with a melee weapon.

This all looks a lot like someone taking Aley's old pirate sword script and trying to make it into a working weapon, instead of a theatrical prop (I did this myself years ago, so yeah, looks reeeeally familiar). Lightsabers tend to be made this way, too.

When I decided to make melee weapons, I just made them shoot people with invisible bullets, timed to die at close range. As for using a sensor, I'd use that to message the opponent when hit, and tell the meter (if using one) that they've been hit (if it works that way).

Pushing is unreliable. And pushing them across the sim is probably a bit unreasonable.

As for left clicking and arrow keys, I'm used to that being how you use a sword outside of Mouselook, not in it.

Also, the misspellings in the listen section of your draw/sheath script will cause it to malfunction. Hope it helps.

Edited by PheebyKatz
Link to comment
Share on other sites

Thank you, very much, for your feedback. Yeah. I've been playing around with the old freebie swordfighting script for years. It's the basis of the script. I've had this script since I started SL in 2008. lol

 

Where are the misspellings in the draw/sheathe script? I'll get those sorted.

 

Yeah. Like I said, for the most part, I've been trying to figure out a third person control scheme that works well while in Third Person Mode. Having to left click and use the movement keys (I use WASD for movement) takes away the ability to use Mouse Steering, which makes moving the avie awkward. I wanted a control scheme that lets you use Mouse Steering while activating the sword strikes in a way that feels comfortable for most players. I'm eager to see what people think of the control scheme.

 

I'm not sure how I feel about the bullet system for melee weapons. I've played with a few that used it. Not quite sure how I felt about it. But I'll definitely consider it. As for pushing, yeah. That's just something that never got changed, as I was focused on the controls, rather than the means of dealing actual damage. I'll be honest, I've been more focused on the controls than in the combat system as a whole. lol! I know I'm not good enough to put together a *real* combat system. I just want to see if I can set up a control scheme that people like and are willing to incorporate into their own combat systems. If I could participate in combat using others' systems, that'd be great. As it stands, it's all Mouselook, which, due to reasons, means I can't participate in the combat. Hence why I've been scratching my head trying to think of a system that will work well in Third Person.

 

I really, really hope that people like the control scheme, or better yet, help me improve on it so it's comfortable for most people to use in Third Person!

Link to comment
Share on other sites

Using a short-range sensor is probably fine, as long as it can communicate somehow with any combat meter you might want to employ. I just have my stuff message them on a negative-numbered channel (to avoid snooping/cheating), and tell the meter they've been hit. Of course, I made the meter to go with it, so it'd always work.

As for invisible bullets, think like a slat of board being thrown at them, that dies on contact, or by the time it's gone out of melee range, whichever comes sooner. Not naming any names, but a lot of fantasy combat sword makers use this approach.

I'd love to see it just come down to having the weapon touch the opponent and registering hits, but attachments are all phantom, just to keep people from getting their eyes poked out at marshmallow roasts and stuff. ^-^;

And despite my edging on snarky with my first reply, because I was like, why is it this old thing again, I agree that making it do what you want is a worthy goal. Even if you end up not liking it as much as the way it worked before, you tried and made it go. And besides, it could actually turn out to be a big improvement.

So yeah, keep us updated and stuff!

Edited by PheebyKatz
Link to comment
Share on other sites

On 3/4/2024 at 9:54 PM, PheebyKatz said:

Using a short-range sensor is probably fine, as long as it can communicate somehow with any combat meter you might want to employ. I just have my stuff message them on a negative-numbered channel (to avoid snooping/cheating), and tell the meter they've been hit. Of course, I made the meter to go with it, so it'd always work.

As for invisible bullets, think like a slat of board being thrown at them, that dies on contact, or by the time it's gone out of melee range, whichever comes sooner. Not naming any names, but a lot of fantasy combat sword makers use this approach.

I'd love to see it just come down to having the weapon touch the opponent and registering hits, but attachments are all phantom, just to keep people from getting their eyes poked out at marshmallow roasts and stuff. ^-^;

And despite my edging on snarky with my first reply, because I was like, why is it this old thing again, I agree that making it do what you want is a worthy goal. Even if you end up not liking it as much as the way it worked before, you tried and made it go. And besides, it could actually turn out to be a big improvement.

So yeah, keep us updated and stuff!

 Well, I hadn't intended to build a whole combat system. Like I said, I was just trying to see if the controls feel okay enough in Third Person Mode for others to adopt the control scheme in their systems. I like the idea of SL combat, but it's all done in First Person, and I can't really do First Person. While the combat system supposedly works in Third Person, the problem is that the strikes are activated by holding down the left mouse button along with the directional keys. This takes away the ability to use Mouse Steering (where you left click on your avatar and drag the mouse left and right to rotate it), which is essential for smooth navigation in Third Person. So my hope is to come up with a control scheme that works in Third Person and lets you use Mouse Steering while still activating the strikes. I'm hoping people like this enough to want to see it in popular combat systems.

Link to comment
Share on other sites

22 hours ago, KeeperS Karu said:

 Well, I hadn't intended to build a whole combat system. Like I said, I was just trying to see if the controls feel okay enough in Third Person Mode for others to adopt the control scheme in their systems. I like the idea of SL combat, but it's all done in First Person, and I can't really do First Person. While the combat system supposedly works in Third Person, the problem is that the strikes are activated by holding down the left mouse button along with the directional keys. This takes away the ability to use Mouse Steering (where you left click on your avatar and drag the mouse left and right to rotate it), which is essential for smooth navigation in Third Person. So my hope is to come up with a control scheme that works in Third Person and lets you use Mouse Steering while still activating the strikes. I'm hoping people like this enough to want to see it in popular combat systems.

I make all my melee work via left click in general that Includes both standard and mouse look clicking. A good method I found was to use gestures. Use left click for your base rotation of moves and use gestures to activate more complex attacks on your next click.

If you really want to do multi key combos. I posted something a while back that was a VERY rough draft of exactly that. I managed to achieve quite a significant number of combinations and there were still more that could be done. If you go back through this forum you will find it. It’s very rough though and not even remotely polished. More of code dump brain storming session.

If you wanted avoid sensors and raycast. You could use llGetRegionList. Then loop through and detect how many avatars are around you, and how many of those are in front of you within X angle.

It works just as well as a sensor and just as quickly.

  • Thanks 1
Link to comment
Share on other sites

49 minutes ago, ItHadToComeToThis said:

[llGetRegionList] It works just as well as a sensor and just as quickly.

llGetRegionList returns up to 100 avatars, in no sensible order; Sensor only up to 20 or so, and sorted by distance. In the (extremely unlikely) case that there are over 100 agents in the region, you may fail to find one even if it's right in front of you.

Link to comment
Share on other sites

15 minutes ago, Quistess Alpha said:

llGetRegionList returns up to 100 avatars, in no sensible order; Sensor only up to 20 or so, and sorted by distance. In the (extremely unlikely) case that there are over 100 agents in the region, you may fail to find one even if it's right in front of you.

This works pretty well each time, iv used it in a system in the past. I was trying to achieve it a number of years ago, and managed to get quite far, but was unsure of how to calculate the angle as it wasn't something I had done before in this way. @Rolig Loon was kind enough to help me figure it out at the time. Though I do get what you are saying about +100 avatars, you would need to figure out a way to factor that in if possible.

avatarInFront(){
    list avatars=llGetAgentList(AGENT_LIST_REGION,[]);
    integer i=-1;
    while(++i<llGetListLength(avatars)){
        list temp=llGetObjectDetails((key)llList2String(avatars,i),[OBJECT_POS]);
        vector myPos=llGetPos();
        vector avdir=llVecNorm((vector)llList2String(temp,0)-myPos);
        vector lookdir=llRot2Fwd(llGetRot());
        float dp=avdir*lookdir;
        if(RAD_TO_DEG*llAcos(dp)<45.0){
            if((key)llList2String(avatars,i)!=llGetOwner()){
                if(llVecDist(myPos,(vector)llList2String(temp,0))<2){
                    llOwnerSay("Found Avatar : "+llKey2Name(llList2Key(avatars,i)));
                }
            }
        }
    }
}

default{
    touch_start(integer x){
        avatarInFront();
    }
}

 

Edited by ItHadToComeToThis
  • Like 1
Link to comment
Share on other sites

2 hours ago, ItHadToComeToThis said:

I make all my melee work via left click in general that Includes both standard and mouse look clicking. A good method I found was to use gestures. Use left click for your base rotation of moves and use gestures to activate more complex attacks on your next click.

If you really want to do multi key combos. I posted something a while back that was a VERY rough draft of exactly that. I managed to achieve quite a significant number of combinations and there were still more that could be done. If you go back through this forum you will find it. It’s very rough though and not even remotely polished. More of code dump brain storming session.

If you wanted avoid sensors and raycast. You could use llGetRegionList. Then loop through and detect how many avatars are around you, and how many of those are in front of you within X angle.

It works just as well as a sensor and just as quickly.

Hm. How'd you solve the problem of needing Mouse Steering at the same time of needing to Left Click? Because the way it's described, you have to stop Mouse Steering in order to make the attack, and the opponent could have already moved away by the time you attack, and you can't react fast enough to go back to Mouse Steering.

Link to comment
Share on other sites

Posted (edited)

You know, I just realized I'm making a big assumption here. I've talked to at least 4 friends recently and found out that, after all these years, they didn't know that Avatar Mouse Steering was a thing. So for people who may not know what in the world I'm referring to, Avatar Mouse Steering is the following:

 

 

 

A quick thing I'd like to share: Avatar Mouse Steering works if you left click and hold on your avatar name tag. So if you have things on you that you might end up clicking if you clicked directly on your avatar, click your name tag instead. If you find you need your name tag to be higher, you can set your name tag higher above you by going (on Firestorm, at least) to Preferences-->Colors-->Name Tags-->Name Tag Z-Offset.

Edited by KeeperS Karu
  • Thanks 1
Link to comment
Share on other sites

16 hours ago, KeeperS Karu said:

A quick thing I'd like to share: Avatar Mouse Steering works if you left click and hold on your avatar name tag. So if you have things on you that you might end up clicking if you clicked directly on your avatar, click your name tag instead. If you find you need your name tag to be higher, you can set your name tag higher above you by going (on Firestorm, at least) to Preferences-->Colors-->Name Tags-->Name Tag Z-Offset.

Damn.  Knew about mouse steering, but I'd forgotten the nametag thing, so haven't been using it — with a tail, wings, and long hair, finding a clear spot for that mouse steering can be a little tricky…  I also keep forgetting you have to click on the avatar (because a game I been playing a bit lately uses it, too, a but a little differently), and accidentally selecting some random pie menu option.  Haven't, like, accidentally deleted or returned a friends house yet, or anything, but, I'm rueing the day…  (Is that even how that word works?  meh, nvm)

Link to comment
Share on other sites

Okay, the nametag thingy is super neato. I get it now. I've never seen combat stuff made with that in mind, like, at all. That I know of.

When you get this working in anything like a satisfactory fashion, please let us know how you made it go. Even if it's just adding a different key to press in the control event or something, to trigger the attack/strike.

This sort of thing is waaay up my alley, and I would love to see it work.

Make it so that it's optional, and can be switched from "normal" mode to mouse steering mode, and I bet you five bucks it catches on somewhere out there. It's a neato idea, and a worthy project, IMO.

Edited by PheebyKatz
Link to comment
Share on other sites

2 hours ago, PheebyKatz said:

Okay, the nametag thingy is super neato. I get it now. I've never seen combat stuff made with that in mind, like, at all. That I know of.

When you get this working in anything like a satisfactory fashion, please let us know how you made it go. Even if it's just adding a different key to press in the control event or something, to trigger the attack/strike.

This sort of thing is waaay up my alley, and I would love to see it work.

Make it so that it's optional, and can be switched from "normal" mode to mouse steering mode, and I bet you five bucks it catches on somewhere out there. It's a neato idea, and a worthy project, IMO.

Ah! Okay! I'll work on it being an optional mode!

 

Right now, things operate so that holding down the forward key in combination with the other directional keys will activate the strikes. I actually like it and find it super comfortable. I decided against using the crouch or jump keys because I wanted to have those available. The crouch key is usually used for blocking, and I want to give my players the ability to jump when they need to. So that left the forward key, and things worked out pretty well. I'm comfortable with it. Now, I'm just trying to see if others are comfortable with it.

Link to comment
Share on other sites

  • 1 month later...

Okay. So I discovered some flaws in my draw/sheathe scripts. The alphas weren't being applied correctly. Fixed the problem I was having, so here are the scripts.

 

The Draw/Sheathe Script For the Sheath:

 

//PREAMBLE: Module Names
//Module 1: Defining Global String Variables - String Parameters
//Module 2: Defining Global Integer Variable - Integer Parameters
//Module 3: The Draw/Sheathe Script
            //Module 3A: Reset the Script Whenever the Object is Rezzed
            //Module 3B: Listen for Commands From the Avatar
            //Module 3C: Actions to Take When the Avatar Delivers the Draw and Sheathe Commands Via Chat
            //Module 3D: Trigger the Sword Draw Sound Effect and Render the Sword Visible or Invisible, As Appropriate


//Module 1: Defining Global String Variables - String Parameters
string g_message;

//Module 2: Defining Global Integer Variable - Integer Parameters
integer listen_handle;

//Module 3: The Draw/Sheathe Script
default
{
    //Module 3A: Reset the Script Whenever the Object is Rezzed
    on_rez(integer start_param)
    {
        llResetScript();
    }
    
    //Module 3B: Listen for Commands From the Avatar
    state_entry()
    {
        llListenRemove(listen_handle);
        listen_handle = llListen(5, "", llGetOwner(), "");
    }
    
    //Module 3C: Actions to Take When the Avatar Delivers the Draw and Sheathe Commands Via Chat  
    listen(integer channel, string name, key id, string message)
        {
            
            g_message = llToLower(message);

            if(g_message == "hdraw")
            {
                llSetTimerEvent(0.25);
            }
            if(g_message == "sdraw")
            {
                llSetTimerEvent(0.25);
            }
            else if(g_message == "hsheathe") 
            {
                llSetTimerEvent(0.75);
            }
            else if(g_message == "ssheathe") 
            {
                llSetTimerEvent(0.75);
            }
        }
    
    //Module 3D: Render the Sword Hilt Visible or Invisible, As Appropriate
    timer()
    {   
    
        if( g_message == "hdraw" )
        {
            llSetAlpha(0.0, ALL_SIDES);
            llSetPrimitiveParams([PRIM_GLTF_BASE_COLOR, ALL_SIDES, "", <1,1,1>, ZERO_VECTOR, 0, <1,1,1>, 0, 1, 1, 0]);
            
        }
        if( g_message == "sdraw" )
        {
            llSetAlpha(0.0, ALL_SIDES);
            llSetPrimitiveParams([PRIM_GLTF_BASE_COLOR, ALL_SIDES, "", <1,1,1>, ZERO_VECTOR, 0, <1,1,1>, 0, 1, 1, 0]);
            
        }
        else if( g_message == "hsheathe" )
        {
            llSetAlpha(1.0, 1);
            llSetAlpha(1.0, 2);
            llSetAlpha(1.0, 3);
            llSetAlpha(1.0, 4);
            llSetPrimitiveParams([PRIM_GLTF_BASE_COLOR, 1, "", <1,1,1>, ZERO_VECTOR, 0, <1,1,1>, 1, 0, 1, 0]);
            llSetPrimitiveParams([PRIM_GLTF_BASE_COLOR, 2, "", <1,1,1>, ZERO_VECTOR, 0, <1,1,1>, 1, 0, 1, 0]);
            llSetPrimitiveParams([PRIM_GLTF_BASE_COLOR, 3, "", <1,1,1>, ZERO_VECTOR, 0, <1,1,1>, 1, 0, 1, 0]);
            llSetPrimitiveParams([PRIM_GLTF_BASE_COLOR, 4, "", <1,1,1>, ZERO_VECTOR, 0, <1,1,1>, 1, 0, 1, 0]);
        }
        else if( g_message == "ssheathe" )
        {
            llSetAlpha(1.0, 1);
            llSetAlpha(1.0, 2);
            llSetAlpha(1.0, 3);
            llSetAlpha(1.0, 4);
            llSetPrimitiveParams([PRIM_GLTF_BASE_COLOR, 1, "", <1,1,1>, ZERO_VECTOR, 0, <1,1,1>, 1, 0, 1, 0]);
            llSetPrimitiveParams([PRIM_GLTF_BASE_COLOR, 2, "", <1,1,1>, ZERO_VECTOR, 0, <1,1,1>, 1, 0, 1, 0]);
            llSetPrimitiveParams([PRIM_GLTF_BASE_COLOR, 3, "", <1,1,1>, ZERO_VECTOR, 0, <1,1,1>, 1, 0, 1, 0]);
            llSetPrimitiveParams([PRIM_GLTF_BASE_COLOR, 4, "", <1,1,1>, ZERO_VECTOR, 0, <1,1,1>, 1, 0, 1, 0]);
        }
        
        llSetTimerEvent(0);
    }
    
}

 

 

And here's the Draw/Sheathe Script for the Melee Weapon:

 

//PREAMBLE: Module Names
//Module 1: Defining Global String Variables - String Parameters
//Module 2: Defining Global Integer Variable - Integer Parameters
//Module 3: The Draw/Sheathe Script
            //Module 3A: Reset the Script Whenever the Object is Rezzed
            //Module 3B: Listen for Commands From the Avatar
            //Module 3C: Actions to Take When the Avatar Delivers the Draw and Sheathe Commands Via Chat
            //Module 3D: Trigger the Sword Draw Sound Effect and Render the Sword Visible or Invisible, As Appropriate


//Module 1: Defining Global String Variables - String Parameters
string g_message;

//Module 2: Defining Global Integer Variable - Integer Parameters
integer listen_handle;

//Module 3: The Draw/Sheathe Script
default
{
    //Module 3A: Reset the Script Whenever the Object is Rezzed
    on_rez(integer start_param)
    {
        llResetScript();
    }
    
    //Module 3B: Listen for Commands From the Avatar
    state_entry()
    {
        llListenRemove(listen_handle);
        listen_handle = llListen(5, "", llGetOwner(), "");
    }
    
    //Module 3C: Actions to Take When the Avatar Delivers the Draw and Sheathe Commands Via Chat  
    listen(integer channel, string name, key id, string message)
        {
            
            g_message = llToLower(message);

            if(g_message == "hdraw")
            {
                llSetTimerEvent(0.25);
            }
            if(g_message == "sdraw")
            {
                llSetTimerEvent(0.25);
            }
            else if(g_message == "hsheathe") 
            {
                llSetTimerEvent(0.75);
            }
            else if(g_message == "ssheathe") 
            {
                llSetTimerEvent(0.75);
            }
        }
    
    //Module 3D: Render the Sword Hilt Visible or Invisible, As Appropriate
    timer()
    {   
    
        if( g_message == "hdraw" )
        {
            llSetAlpha(0.0, ALL_SIDES);
            llSetPrimitiveParams([PRIM_GLTF_BASE_COLOR, ALL_SIDES, "", <1,1,1>, ZERO_VECTOR, 0, <1,1,1>, 0, 1, 1, 0]);
            
        }
        if( g_message == "sdraw" )
        {
            llSetAlpha(0.0, ALL_SIDES);
            llSetPrimitiveParams([PRIM_GLTF_BASE_COLOR, ALL_SIDES, "", <1,1,1>, ZERO_VECTOR, 0, <1,1,1>, 0, 1, 1, 0]);
            
        }
        else if( g_message == "hsheathe" )
        {
            llSetAlpha(1.0, 1);
            llSetAlpha(1.0, 2);
            llSetAlpha(1.0, 3);
            llSetAlpha(1.0, 4);
            llSetPrimitiveParams([PRIM_GLTF_BASE_COLOR, 1, "", <1,1,1>, ZERO_VECTOR, 0, <1,1,1>, 1, 0, 1, 0]);
            llSetPrimitiveParams([PRIM_GLTF_BASE_COLOR, 2, "", <1,1,1>, ZERO_VECTOR, 0, <1,1,1>, 1, 0, 1, 0]);
            llSetPrimitiveParams([PRIM_GLTF_BASE_COLOR, 3, "", <1,1,1>, ZERO_VECTOR, 0, <1,1,1>, 1, 0, 1, 0]);
            llSetPrimitiveParams([PRIM_GLTF_BASE_COLOR, 4, "", <1,1,1>, ZERO_VECTOR, 0, <1,1,1>, 1, 0, 1, 0]);
        }
        else if( g_message == "ssheathe" )
        {
            llSetAlpha(1.0, 1);
            llSetAlpha(1.0, 2);
            llSetAlpha(1.0, 3);
            llSetAlpha(1.0, 4);
            llSetPrimitiveParams([PRIM_GLTF_BASE_COLOR, 1, "", <1,1,1>, ZERO_VECTOR, 0, <1,1,1>, 1, 0, 1, 0]);
            llSetPrimitiveParams([PRIM_GLTF_BASE_COLOR, 2, "", <1,1,1>, ZERO_VECTOR, 0, <1,1,1>, 1, 0, 1, 0]);
            llSetPrimitiveParams([PRIM_GLTF_BASE_COLOR, 3, "", <1,1,1>, ZERO_VECTOR, 0, <1,1,1>, 1, 0, 1, 0]);
            llSetPrimitiveParams([PRIM_GLTF_BASE_COLOR, 4, "", <1,1,1>, ZERO_VECTOR, 0, <1,1,1>, 1, 0, 1, 0]);
        }
        
        llSetTimerEvent(0);
    }
    
}

Haven't fiddled with the main melee weapon script in a while.

Link to comment
Share on other sites

All righty! Thanks to help from someone (I need to ask them permission to mention them specifically), I was able to modify the melee weapon script so that by clicking the weapon, the player can choose which control scheme they want to use: Standard or mine. Here's the modified script. As usual, I'd love for some feedback on it. Eventually, I'm going to ask questions on what it means to "optimize" a script and how I can go about doing that for this script. But right now, I want to make sure it all works the way it's supposed to. And if it does, is there a better way to approach the situation? I have a way of complicating things more than they need to be. xD

 

//PREAMBLE: Module Names
//Module 1: Defining Global String Variables - Animation Names
//Module 2: Defining Global String Variables - Sound Effect Names
//Module 3: Defining Global String Variables - Bloodsplatter Object Name
//Module 4: Defining Global Variables - MISC
     //Module 4A: Attack Types
     //Module 4B: Weapon Safety Variables
     //Module 4C: Weapon Control Scheme Variables
//Module 5: The Safety & Release/Reset Functions
    //Module 5A: Safety On
    //Module 5B: Safety Off
    //Module 5C: Release Controls and Reset Script
//Module 6: The Double Tap Code
    //Module 6A: Defining the Double-Tap Global Vairables
    //Module 6B: Obtaining the Time the Key Was Pressed
    //Module 6C: Comparing the Time Between Key Presses
    //Module 6D: Resetting the storedTime Variable
    //Module 6E: Double Tap
//Module 7: The Sword Script
    //Module 7A: The Default State of the Sword Object When the Script Is First Executed
        //Module 7Aa: The Sword's Status When the Script is Reset - It Cannot Be Grabbed and Physically Dragged; Instruct Owner To Touch Sword For Options
        //Module 7Ab: Touch Weapon To Choose Control Scheme
        //Module 7Ac: Actions to Take When the Sword is Attached and Detached From the Avatar
        //Module 7Ad: If Permission Has Been Given, Take Over Keyboard Functions
        //Module 7Ae: Menu Choices
        //Module 7Af: Actions to Perform When the Timer Event is Triggered
    //Module 7B: When In The Keeper State, Use Keeper's Third Person Control Scheme
        //Module 7Ba: Actions To Take When The Weapon Is Attached/Detached    
        //Module 7Bb: Preliminary Actions On Entering State
        //Module 7Bc: What To Do When The Weapon Is Drawn & Sheathed
        //Module 7Bd: The Control Scheme, Keeper's Third Person    
        //Module 7Be: What To Do When The Object Changes Owner
    //Module 7C: When In State Standard, Use Standard Control Scheme
        //Module 7Ca: Actions To Take When The Weapon Is Attached/Detached    
        //Module 7Cb: Preliminary Actions On Entering State
        //Module 7Cc: What To Do When The Weapon Is Drawn & Sheathed
        //Module 7Cd: The Control Scheme, Standard Controls
        //Module 7Ce: What To Do When The Object Changes Owner
    //Module 7D: What To Do When When The Weapon Controls Are Used
        //Module 7Da: Setting The Timers    
        //Module 7Db: What Happens When The Timers Go Off    
        //Module 7Dc: Actions to Perform if There's a Valid Target within the Predefined Sensor Range
        //Module 7Dd: Actions To Take When There Is No Target Within Range

//Module 1: Defining Global String Variables - Animation Names
string fwdanim = "overhead_strike_exaggerated P6";
string bckanim = "high_kick P6";
string rotrightanim = "diagonal_left_strike_exag P6";
string rotleftanim = "diagonal_right_strike_exag P6";
string straferightanim = "upward_left_strike_exag";
string strafeleftanim = "upward_right_strike_exag";
string pgdwnanim = "basic_angle_block";
string pgupanim = "backflip";

//Module 2: Defining Global String Variables - Sound Effects Names
string swdswing = "swordswing01";
string swdconnectflsh = "sword_flesh_01";
//string block swing; - If different from the other sound effects, enter them, here, as well as in the appropriate area of the code, below
string blockconnect = "sword05";
//string kick swing; - If different from the other sound effects, enter them, here, as well as in the appropriate area of the code, below
string kickconnect = "Punch04";

//Module 3: Defining Global String Variables - Bloodsplatter Object Name
string bloodsplatter = "!bloodsplatter";

//Module 4: Defining Global Variables - MISC

    //Module 4A: Attack Types
    integer SWORDFWD = 1;
    integer SWORDRGT = 2;
    integer SWORDLFT = 3;
    integer BLOCK = 4;
    integer KICK = 5;
    integer SPECIALATK = 6;
    integer strike_type;
    
    //Module 4B: Weapon Safety Variables
    
    string g_message;
    integer listen_handle;
    integer SAFETY_ON = TRUE;
    integer perm;
    
    //Module 4C: Weapon Control Scheme Variables
    
    integer gListener;
    string menuText = "\nChoose the movement controls you wish to use."; // you can change this to say whatever you want
    list menuButtons = ["Keeper","Standard","Cancel"]; // these are the buttons that will appear in the menu, you can change these
    integer menuChan; // channel that the dialog box talks on, will make this some large random negative number later on
    integer menuUsed = FALSE;
    integer KeeperS = FALSE;
    integer standardS = FALSE;
    
//Module 5: The Safety & Release/Reset Functions

    //Module 5A: Safety On
    SAFETYON()
    {
        SAFETY_ON = TRUE; // switch the safety on
        llSay(0, "releasing controls");
        llReleaseControls();
    }

    //Module 5B: Safety Off
    SAFETYOFF()
    {
        SAFETY_ON = FALSE; // switch the safety off
        llRequestPermissions(llGetOwner(),PERMISSION_TAKE_CONTROLS|PERMISSION_TRIGGER_ANIMATION); // request permissions
        integer perm = llGetPermissions();
            
            if (perm != (PERMISSION_TAKE_CONTROLS | PERMISSION_TRIGGER_ANIMATION))
            {
                llRequestPermissions(llGetOwner(),PERMISSION_TAKE_CONTROLS|PERMISSION_TRIGGER_ANIMATION); // request permissions
            }
            else
            {
                llTakeControls(CONTROL_ML_LBUTTON | CONTROL_LBUTTON | CONTROL_UP | CONTROL_FWD | CONTROL_BACK | CONTROL_ROT_LEFT | CONTROL_LEFT | CONTROL_RIGHT | CONTROL_ROT_RIGHT, TRUE, TRUE);
            }
    }
    
    //Module 5C: Release Controls and Reset Script
    ReleaseReset()
    {
        llSay(0, "releasing controls");
        llReleaseControls();
        llResetScript();
    }
    
//Module 6: The Double Tap Code

    //Module 6A: Defining the Double-Tap Global Vairables
    float strTime;
    float time;
    float storedTime;               
    float recentTime; 
    float interval = 1.25;

    //Module 6B: Obtaining the Time the Key Was Pressed
    getSeconds()
    {
        string timestamp    = llGetTimestamp();
        string subTime      = llGetSubString(timestamp, 19, 25);
        float wallclock     = llGetWallclock();
        strTime = (float)subTime + wallclock;
    }
    
    //Module 6C: Comparing the Time Between Key Presses              
    compareTimes(float stored, float recent)
    {
        time = recent - stored;
    }
    
    //Module 6D: Resetting the storedTime Variable
    resetStored()
    {
    storedTime = 0;
    }
    
    //Module 6E: Double Tap
    
    FStrike()
    {
        if (KeeperS == TRUE)
        {
        if ( time <= interval | time > interval )
        {
            llStartAnimation(fwdanim);
            strike_type = SWORDFWD;
        }
        }
        else if (standardS = TRUE)
        {
            llStartAnimation(fwdanim);
            strike_type = SWORDFWD;
        }
    }
    
    BStrike()
    {
        if ( time >= interval )
        {
            llStartAnimation(bckanim);
            strike_type = KICK;
        }
        else
        {
            llStartAnimation(fwdanim);
            strike_type = KICK;
        }
    }
    
    RLeft()
    {
        if ( time <= interval )
        {
            llStartAnimation(rotleftanim);
            strike_type = SWORDLFT;
        }
        else
        {
            llStartAnimation(strafeleftanim);
            strike_type = SWORDLFT;
        }
    }
    SLeft()
    {
        if ( time <= interval )
        {
            llStartAnimation(strafeleftanim);
            strike_type = SWORDLFT;
        }
        else
        {
            llStartAnimation(rotleftanim);
            strike_type = SWORDLFT;
        }
    }
    RRight()
    {
        if( time <= interval)
        {
            llStartAnimation(rotrightanim);
            strike_type = SWORDRGT;
        }
        else
        {
            llStartAnimation(straferightanim);
            strike_type = SWORDRGT;
        }
    }
    SRight()
    {
        if ( time <= interval )
        {
            llStartAnimation(straferightanim);
            strike_type = SWORDRGT;
        }
        else
        {
            llStartAnimation(rotrightanim);
            strike_type = SWORDRGT;
        }
    }

//Module 7: The Sword Script


//Module 7A: The Default State of the Sword Object When the Script Is First Executed
default
{
    //Module 7Aa: The Sword's Status When the Script is Reset - It Cannot Be Grabbed and Physically Dragged; Instruct Owner To Touch Sword For Options
    state_entry()
    {
        llSetStatus(STATUS_BLOCK_GRAB, TRUE);
        llOwnerSay("Touch the weapon to choose which movement controls you would like to use.");
    }
    
    //Module 7Ab: Touch Weapon To Choose Control Scheme
    touch_end(integer num_detected)
    {
        menuChan = (integer)(llFrand(999999.0) * -1);  // this just comes up with some big random negative number to use as the channel for the menu to work on
        llListenRemove(gListener);
        gListener = llListen(menuChan,"",llGetOwner(),"");   
        llDialog(llGetOwner(),menuText,menuButtons,menuChan);
        llSetTimerEvent(30.0); // just in case the person does not make a selection after clicking the weapon   
    }
    
    //Module 7Ac: Actions to Take When the Sword is Attached and Detached From the Avatar
    attach(key on)
    {
        if (on != NULL_KEY)
        {
            integer perm = llGetPermissions();
            
            if (perm != (PERMISSION_TAKE_CONTROLS | PERMISSION_TRIGGER_ANIMATION))
            {
                llRequestPermissions(on, PERMISSION_TAKE_CONTROLS | PERMISSION_TRIGGER_ANIMATION);
            }
            else
            {
                llTakeControls(CONTROL_ML_LBUTTON | CONTROL_LBUTTON | CONTROL_UP | CONTROL_FWD | CONTROL_BACK | CONTROL_ROT_LEFT | CONTROL_LEFT | CONTROL_RIGHT | CONTROL_ROT_RIGHT, TRUE, TRUE);
            }
            
        }
        else
        {
            //llSay(0, "releasing controls");
            //llReleaseControls();
            ReleaseReset();           
        }
    }
    
    //Module 7Ad: If Permission Has Just Been Given, Take Over Keyboard Functions
    run_time_permissions(integer perm)
    {
        if (perm)
        {
            llTakeControls(CONTROL_ML_LBUTTON | CONTROL_LBUTTON | CONTROL_UP | CONTROL_FWD | CONTROL_BACK | CONTROL_ROT_LEFT | CONTROL_LEFT | CONTROL_RIGHT | CONTROL_ROT_RIGHT | CONTROL_DOWN, TRUE, TRUE);
        }
    }
    
    //Module 7Ae: Menu Choices
    
    listen(integer channel, string name, key id, string message)
        {   
            if(channel == menuChan)
            {
                if(message == "Cancel") // give the user an opportunity to cancel out of the menu
                {
                    menuUsed = TRUE;
                    return;
                }
                if(message == "Keeper") // if you change what the button name is on line 3, change this to match
                {
                    menuUsed = TRUE;
                    state Keeper; // go to the keeper state
                }
                if(message == "Standard") // if you change what the button name is on line 3, change this to match
                {
                    menuUsed = TRUE;
                    state standard; // go to the 'usual' movement state
                }
            }
        }  
    
    //Module 7Af: Actions to Perform When the Timer Event is Triggered
    timer()
    {
        if (menuUsed == TRUE)
        {
        }
        else
        {
            llListenRemove(gListener);
            llResetScript();
        }
        llSetTimerEvent(0.0);
    }
    
}

//Module 7B: When In The Keeper State, Use Keeper's Third Person Control Scheme
state Keeper
{
    //Module 7Ba: Actions To Take When The Weapon Is Attached/Detached
    attach (key on)
    {
        if(on)
        {
        }
        else
        {
            ReleaseReset();
        }
    }
    
    //Module 7Bb: Preliminary Actions On Entering State
    state_entry()
    {   
        llListenRemove(listen_handle);
        listen_handle = llListen(5, "", llGetOwner(), "");
        SAFETYOFF();
        KeeperS = TRUE;
    }
    
    //Module 7Bc: What To Do When The Weapon Is Drawn & Sheathed
    listen(integer channel, string name, key id, string message)
        {   
        if(channel == 5)
        {
            g_message = llToLower(message);

            if( g_message == "hdraw" )
            {
                SAFETYOFF();
            }
            if( g_message == "sdraw" )
            {
                SAFETYOFF();
            }
            else if(g_message == "hsheathe") 
            {
                SAFETYON();
            }
            else if(g_message == "ssheathe") 
            {
                SAFETYON();
            }
        }
    }
    
    //Module 7Bd: The Control Scheme, Keeper's Third Person
    control(key owner, integer held, integer change)
    {

            if (held & (CONTROL_ML_LBUTTON | CONTROL_FWD))
            {
                if (change & held & CONTROL_UP)
                {
                    llApplyImpulse(<0,0,3.5>,FALSE);
                    llStartAnimation(pgupanim);
                    strike_type = SPECIALATK;
                    state WeaponStrike;
                }
                if (change & held & CONTROL_FWD)
                {
    
                    getSeconds();
                    recentTime = strTime;                                                    
                    compareTimes(storedTime, recentTime);
                    storedTime = recentTime;   
                    FStrike();                          
                    state WeaponStrike;
                }
                if (change & held & CONTROL_ROT_LEFT)
                {
                    getSeconds();
                    recentTime = strTime;                                                    
                    compareTimes(storedTime, recentTime);
                    storedTime = recentTime; 
                    SLeft();
                    state WeaponStrike;
                }
                if (change & held & CONTROL_LEFT)
                {
                    getSeconds();
                    recentTime = strTime;                                                    
                    compareTimes(storedTime, recentTime);
                    storedTime = recentTime;
                    RLeft();                            
                    state WeaponStrike;
                }
                if (change & held & CONTROL_ROT_RIGHT)
                {
                    getSeconds();
                    recentTime = strTime;                                                    
                    compareTimes(storedTime, recentTime);
                    storedTime = recentTime; 
                    SRight();                            
                    state WeaponStrike;
                }
                if (change & held & CONTROL_RIGHT)
                {
                    getSeconds();
                    recentTime = strTime;                                                    
                    compareTimes(storedTime, recentTime);
                    storedTime = recentTime;  
                    RRight();                            
                    state WeaponStrike;
                }
                 if (change & held & CONTROL_BACK)
                {
                    getSeconds();
                    recentTime = strTime;                                                    
                    compareTimes(storedTime, recentTime);
                    storedTime = recentTime;   
                    BStrike();                            
                    state WeaponStrike;
                }
            }
            if (~held & change & (CONTROL_ML_LBUTTON | CONTROL_FWD))
            {
                llStopAnimation(pgdwnanim);
            }
            if (held & change & CONTROL_DOWN)
                {   
                    llStartAnimation(pgdwnanim);
                    llTriggerSound(swdswing, 1.0);
                    llSetTimerEvent(0.01);
                    strike_type = BLOCK;
                    llMoveToTarget(llGetPos(), 0.25);
                    llSleep(1.0);
                    llStopMoveToTarget();
                }
            if (~held & change & CONTROL_DOWN)
                {   
                    llStopAnimation(pgdwnanim);
                }

    }
    
    //Module 7Be: What To Do When The Object Changes Owner
    changed(integer change)
    {
        if(change & CHANGED_OWNER) // reset the script when a new person owns the weapon
        {
            llResetScript();
        }
    }
}

//Modeul 7C: When In State Standard, Use Standard Control Scheme
state standard
{
    //Module 7Ca: Actions To Take When The Weapon Is Attached/Detached
    attach (key on)
    {
        if(on)
        {
        }
        else
        {
            ReleaseReset();
        }
    }
    
    //Module 7Cb: Preliminary Actions On Entering State
    state_entry()
    {   
        llListenRemove(listen_handle);
        listen_handle = llListen(5, "", llGetOwner(), "");
        SAFETYOFF();
        standardS = TRUE;
    }
    
    //Module 7Cc: What To Do When The Weapon Is Drawn & Sheathed
    listen(integer channel, string name, key id, string message)
        {   
        if(channel == 5)
        {
            g_message = llToLower(message);

            if( g_message == "hdraw" )
            {
                SAFETYOFF();
            }
            if( g_message == "sdraw" )
            {
                SAFETYOFF();
            }
            else if(g_message == "hsheathe") 
            {
                SAFETYON();
            }
            else if(g_message == "ssheathe") 
            {
                SAFETYON();
            }
        }
    }
    
    //Module 7Cd: The Control Scheme, Standard Controls
    control(key owner, integer held, integer change)
    {

            if (held & (CONTROL_ML_LBUTTON | CONTROL_LBUTTON))
            {
                if (change & held & CONTROL_UP)
                {
                    llApplyImpulse(<0,0,3.5>,FALSE);
                    llStartAnimation(pgupanim);
                    strike_type = SPECIALATK;
                    state WeaponStrike;
                }
                if (change & held & CONTROL_FWD)
                {
    
                    getSeconds();
                    recentTime = strTime;                                                    
                    compareTimes(storedTime, recentTime);
                    storedTime = recentTime;   
                    FStrike();
                    state WeaponStrike;
                }
                if (change & held & CONTROL_ROT_LEFT)
                {
                    getSeconds();
                    recentTime = strTime;                                                    
                    compareTimes(storedTime, recentTime);
                    storedTime = recentTime;   
                    SLeft();
                    state WeaponStrike;
                }
                if (change & held & CONTROL_LEFT)
                {
                    getSeconds();
                    recentTime = strTime;                                                    
                    compareTimes(storedTime, recentTime);
                    storedTime = recentTime;   
                    RLeft();
                    state WeaponStrike;
                }
                if (change & held & CONTROL_ROT_RIGHT)
                {
                    getSeconds();
                    recentTime = strTime;                                                    
                    compareTimes(storedTime, recentTime);
                    storedTime = recentTime;   
                    SRight();
                    state WeaponStrike;
                }
                if (change & held & CONTROL_RIGHT)
                {
                    getSeconds();
                    recentTime = strTime;                                                    
                    compareTimes(storedTime, recentTime);
                    storedTime = recentTime;   
                    RRight();
                    state WeaponStrike;
                }
                 if (change & held & CONTROL_BACK)
                {
                    getSeconds();
                    recentTime = strTime;                                                    
                    compareTimes(storedTime, recentTime);
                    storedTime = recentTime;   
                    BStrike();                            
                    state WeaponStrike;
                }
            }
            if (~held & change & (CONTROL_ML_LBUTTON | CONTROL_LBUTTON))
            {
                llStopAnimation(pgdwnanim);
            }
            if (held & change & CONTROL_DOWN)
                {   
                    llStartAnimation(pgdwnanim);
                    llTriggerSound(swdswing, 1.0);
                    llSetTimerEvent(0.01);
                    strike_type = BLOCK;
                    llMoveToTarget(llGetPos(), 0.25);
                    llSleep(1.0);
                    llStopMoveToTarget();
                }
            if (~held & change & CONTROL_DOWN)
                {   
                    llStopAnimation(pgdwnanim);
                }

    }
    changed(integer change)
    {
        if(change & CHANGED_OWNER) // reset the script when a new person owns the weapon 
        {
            llResetScript();
        }
    }
}

//Module 7D: What To Do When When The Weapon Controls Are Used
state WeaponStrike
{
    //Module 7Da: Setting The Timers
    state_entry()
    {
        if (strike_type == KICK | strike_type == SPECIALATK)
        {
            llSetTimerEvent(0.25);
        }
        else
        {
            llSetTimerEvent(0.75);
        }
        //llOwnerSay("Test");
    }
    
    //Module 7Db: What Happens When The Timers Go Off
    timer()
    {
        if (strike_type == SWORDFWD)
        {
            llTriggerSound(swdswing, 1.0);
            llSensor("", "", ACTIVE | AGENT, 3.0, PI_BY_TWO*0.5);
        }
        if (strike_type == SWORDRGT)
        {
            llTriggerSound(swdswing, 1.0);
            llSensor("", "", ACTIVE | AGENT, 3.0, PI_BY_TWO);
        }
        if (strike_type == SWORDLFT)
        {
            llTriggerSound(swdswing, 1.0);
            llSensor("", "", ACTIVE | AGENT, 3.0, PI_BY_TWO);
        }
        if (strike_type == BLOCK)
        {
            llSensor("", "", ACTIVE | AGENT, 2.0, PI_BY_TWO);
        }
        if (strike_type == KICK)
        {
            llTriggerSound(swdswing, 1.0);
            llSensor("", "", ACTIVE | AGENT, 3.0, PI_BY_TWO*0.5);
        }
        if (strike_type == SPECIALATK)
        {
            llTriggerSound(swdswing, 1.0);
            llSensor("", "", ACTIVE | AGENT, 3.0, PI_BY_TWO*0.5);
        }
        llSetTimerEvent(0.0);
    }
    
    //Module 7Dc: Actions to Perform if There's a Valid Target within the Predefined Sensor Range
    sensor(integer tnum)
    {
        vector dir = llDetectedPos(0) - llGetPos();
        dir.z = 0.0;
        dir = llVecNorm(dir);
        rotation rot = llGetRot();
        
        if (strike_type == SWORDFWD)
        {
            llTriggerSound(swdconnectflsh, 1.0);
            llRezObject(bloodsplatter,llDetectedPos(0),<0,0,0>,ZERO_ROTATION,TRUE);
            dir += llRot2Up(rot);
            dir *= 200.0;
        }
        else if (strike_type == SWORDRGT)
        {
            llTriggerSound(swdconnectflsh, 1.0);
            llRezObject(bloodsplatter,llDetectedPos(0),<0,0,0>,ZERO_ROTATION,TRUE);
            dir += dir;
            dir *= 100.0;
        }
        else if (strike_type == SWORDLFT)
        {
            llTriggerSound(swdconnectflsh, 1.0);
            llRezObject(bloodsplatter,llDetectedPos(0),<0,0,0>,ZERO_ROTATION,TRUE);
            dir -= llRot2Left(rot);
            dir *= 100.0;
        }
        else if (strike_type == KICK)
        {
            llTriggerSound(kickconnect, 1.0);
            dir += dir;
            dir *= 100.0;
        }
        else if (strike_type == BLOCK)
        {
            llTriggerSound(blockconnect, 1.0);
        }
        else if (strike_type == SPECIALATK)
        {
            llTriggerSound(swdconnectflsh, 1.0);
            llRezObject(bloodsplatter,llDetectedPos(0),<0,0,0>,ZERO_ROTATION,TRUE);
        }
        strike_type= 0;
        if (standardS == TRUE)
        {
            state standard;
        }
        else if (KeeperS == TRUE)
        {
            state Keeper;
        }
    }
    
    //Module 7Dd: Actions To Take When There Is No Target Within Range
    no_sensor()
    {
        if (standardS == TRUE)
        {
            state standard;
        }
        else if (KeeperS == TRUE)
        {
            state Keeper;
        }
    }
}

 

Link to comment
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
 Share

×
×
  • Create New...