SBBJT 0.1

Selfbondage software and other kinky developments

Moderators: Riddle, Shannon SteelSlave

johns1234
*
Posts: 45
Joined: 22 Dec 2015, 01:32

SBBJT 0.1

Post by johns1234 »

This is my take on the blow job trainer.
A few preambles:
- I cranked this out in the last three days - use at own risk.
- I have no insight into the older, existing programs the camera routine is OK, but maybe I do not know all the tricks of the trade (maybe Kevlar can share that part of the code). Testing is crucial.
- This is Windows only - sorry MAC/Linux users.
- I included all the source code for all interested people - feel free to make it your own.

Two missing features from older programs are:
- Respite for having X sucks per minute with a failure rate less than Y% does not work yet. (The settings are there, but I did not get to implement them)
- There is no slideshow while you wait to be released (but as on older version capturing did not work either this is not really lacking compared, I guess)

Functionality compared to the other programs is the same. I do not claim having invented any of this and just took all the rules and settings of the other programs and incorporated them best I could.
The program is lacking a bit in positioning the regions, but I rather went for session functionality instead of spending time on having some drag and resize via mouse.
The screens have a lot of explanations as well as the readme. But just so you know what you are downloading I will be somewhat verbose here as well:

OpenCD - program to open the CD tray
CloseCD - program to close the CD tray
EdimaxPlug - program to turn on/off Edimax power plugs in your WIFI
VoiceFileGenerator - creates wav files with computer voice
SBBJT - self bondage blow job trainer v0.1

The trainer works as before:
1) Set camera resolution
2) Define the test regions, use uniform colored regions for best results (check the readme.txt, check the tips for good lighting and so forth)
3) Define your session settings, the settings are pretty much the same as in the other programs.
4) Set your release method, there is none included, you need to execute a program. I believe modularizing this into programs is a good way which is why I included the little helper programs.
5) This is new: create session event actions
* HeadWarning - The rule 'Head must stay in mouth' is enabled and
the head is not covered. This event is raised every 2 seconds until
the head is covered again.
* SessionStarted - The session is started and is idle until the start
delay has elapsed.
* StartDelayElapsed - The session startup time is over and the action
starts. [Example: You could start a program to activate an electro
magnet to lock things down here.]
* RespiteStarted - You have earned rest. [Example: Activate something
pleasant at this point ... it won't be long]
* RespiteEnded - Back to action, you can use this event to reverse
whatever you did in RespiteStarted.
* SuckStarted - Command to suck was given.
* SuckSuccessful - Suck was accomplished.
* SuckFailed - You failed to complete. This event is raised in addition
to all of the other failure events.
* SuckFailedCheater - The 'Cheat check' rule is enabled and
the suck area was covered, but not the head area.
* SuckFailedFaster - You failed to perform the suck within the
maximum allowed time.
* DeepThroatStarted - The command to do a DT was given.
* DeepThroatMinTime - You reached the minimum time for a deep throat.
* DeepThroatHeld - You held for over a second past the minimum time.
[Example: This is an evil spot for a punishment, you will earn X
sucks reduced when you hold longer, but maybe 20% of the time you
try you get shocked]
* DeepThroatFailed - You failed to complete. This event is raised in
addition to all of the other failure events.
* DeepThroatFailedTooLong - Deep throats have a maximum hold time, so
that you cannot just hold your breath and gain 20 sucks reduced as
a reward. If you exceeed the maximum time the DT will not count and
you will be punished.
* DeepThroatFailedStayDown - You started the DT and went all the way
down, but you did not achieve the minimum hold time.
* DeepThroatFailedDeeper - You started the DT and went to the suck
region, but failed to cover the deep region.
* DeepThroatFailedCheater - The 'Cheat check' rule is enabled and
the deep area was covered, but suck or head region was not.
* DeepThroatFailedFaster - You failed to start the DT within the
maximum allowed time.
* DeepThroatSuccessful - DT was accomplished.
* Finished - The session has ended and you will be waiting for release.
* Released - The session is over.
* SessionTimer - This event fires every second while in action - after
StartDelayElapsed and before Finished. It does also not fire during
Respite.
* FinishTimer - This event fires every second while waiting for release.

For all of these events you can enable to execute a program and optional as a random chance (less than 100%).
Like in the example above: Get punished for trying to earn less sucks holding a DT more then required.

I used v1 and it crashed on me mid session, so I wrote this.
Let me know what you think and don't be stupid using this, make test runs, have backups, you know ....

SBBJT v0.1
https://mega.nz/#!ZxQyUIJK!XxmNnSZuTko0 ... kejI2j9t3c [updated 3/6/16]
(password for unzipping is the same as for the other BoundAnna programs)
hannah1
*
Posts: 17
Joined: 07 Sep 2014, 08:40

Re: SBBJT 0.1

Post by hannah1 »

looks fun
Phoenix
*
Posts: 44
Joined: 12 Mar 2016, 11:07
Location: UK

Re: SBBJT 0.1

Post by Phoenix »

Hi johns1234

for 3 days work you've done a really good job!! I've run several test scenarios and all have worked without issues.

I have found one bug though. Where you have the last X set as DT this isn't enforced where you have a reward for completing a DT. For example you could have the last 5 sucks set as DT but on completing the first and holding for a second or two longer you get a total reward of 4 bringing you to the end of the session.

I've taken a look through the code and even though I'm relatively new to C# I found it relatively easy to understand.

In the class:
Session
in the method:
OnDeepThroatSuccessful()

A suggestion for a modification to the code is below. I've done some tests and it appears to work correctly.

Some thoughts on future development expansions:
  • Have a second DT region with a % of DT that must meet this.
  • Have the option to save a configuration so it can be shared as an assignment
    • Option of setting a password to a saved configuration. Setup tabs would be hidden on load unless unlocked. Might need an obscured/encoded settings file though
    • Have an option to turn off the display of regions on the session image. On Setup (1) Camera, an outline showing the entire area covered by the coded regions to aid in assignment setup
  • Add the concept of having to do multiple BJs in a session
    • Could make each a re randomisation of settings
    • Could have preprogrammed BJs within each session
Hope you like the suggestions. Happy to help as well if you'd like.

Phoenix

Code: Select all

        private void OnDeepThroatSuccessful()
        {
            int rewardCount = 0;
            int reward = 0;
            this.PlaySound("DeepThroatSuccessful");
            this.logger.Log("EVENT - DeepThroatSuccessful");
            this.ExecuteEvent("DeepThroatSuccessful");

            this.suckCompleted = DateTime.Now;
            this.deepThroatsTotal++;
            this.deepThroatsSuccessful++;
            this.deepThroatsConsecutiveNoFail++;
            this.sucksRemaining--;

            this.consecutiveFails = 0;

            this.respiteConsecutiveNoFail++;

            this.logger.Log("deep throat successful");
            this.logger.Log(String.Format("new remaining sucks = {0}", this.sucksRemaining));

            
            if (this.settings.RewardDTReduceSucksByX > 0)
            {
                // reward DT
                rewardCount += this.settings.RewardDTReduceSucksByX;
                
                this.logger.Log(String.Format("qualifies for {0} sucks reward", this.settings.RewardDTReduceSucksByX));
            }

            if (this.settings.RewardHeldDTReduceSucksByXPerSecondHeld > 0 && this.deepThroatHeldTimeReached)
            {
                // reward held time
                TimeSpan heldPastMinTime = TimeSpan.FromSeconds((DateTime.Now - this.deepThroatHoldStart).TotalSeconds - this.deepThroatHoldMinTime);
                reward = this.settings.RewardHeldDTReduceSucksByXPerSecondHeld * (int)heldPastMinTime.TotalSeconds;
                rewardCount += reward;
                this.logger.Log(String.Format("qualifies for {0} sucks reward for time held", reward));
            }

            if (this.settings.RewardConsecutiveDTReduceSucksByX > 0 && this.settings.RewardConsecutiveDTCount < this.deepThroatsConsecutiveNoFail)
            {
                // reward consecutive DTs
                this.deepThroatsConsecutiveNoFail = 0;
                rewardCount += this.settings.RewardConsecutiveDTReduceSucksByX;
                
                this.logger.Log(String.Format("qualifies for {0} sucks reward for {1} consecutive DTs", this.settings.RewardConsecutiveDTReduceSucksByX, this.settings.RewardConsecutiveDTCount));
            }

            if (this.sucksRemaining > this.settings.DTAtLastX && rewardCount > 0)
            {
                if (this.sucksRemaining - rewardCount < this.settings.DTAtLastX)
                {
                    reward = rewardCount - ((rewardCount + this.settings.DTAtLastX)- this.sucksRemaining);
                    this.sucksRemaining -= reward;
                    this.logger.Log(String.Format("Only rewarding {0} sucks of {1} as the last {2} sucks are all to be DTs", reward, rewardCount, this.settings.DTAtLastX));
                } else
                {
                    this.sucksRemaining -= rewardCount;
                    this.logger.Log(String.Format("Rewarding {0} sucks, now {1} sucks remaining", rewardCount, this.sucksRemaining));
                }
            } else
            {
                this.logger.Log(String.Format("Skipping reward {0} sucks as remaining {1} sucks are all to be DT", rewardCount, this.sucksRemaining));
            }
            this.State = SessionState.Wait;
        }
pansexual
**
Posts: 116
Joined: 28 Feb 2010, 23:45

Re: SBBJT 0.1

Post by pansexual »

Thanks a lot for all that work. I am looking into it. One of the most interesting things for me so far, your EdimaxPlug. I didn't even know something like this existed. Now I have two Edimax SP-1101W and can trigger each off or on with a simple command. Still got to make it work, but I got my Estim and my Cane unit in mind. :twisted: Thank you so much, I was looking for a simple way to trigger some punishment, and now it seems so easy. Thank you, thank you, thank you. :D
Plan ahead. Don't be overambitious. Slowly step by step. Play safe. Have fun. And tell us.
johns1234
*
Posts: 45
Joined: 22 Dec 2015, 01:32

Re: SBBJT 0.1

Post by johns1234 »

Glad you like it and thanks for testing it and even providing the fix. The code is written pretty straightforward as I just wrote it all pretty quickly. I can probably integrate a few of these improvements and the fix in the next days. Another addition I was thinking of is a report card like a score how well you did.
Another little program I have written - I do not know if I included it but I will add it to the next zip - is to play sound to a specific soundcard other than the default. I am not a fan of soldering and so forth, so I rather use something like a USB speaker which is recognized as a different soundcard to have multiple outputs, e.g. for sound triggered e-stim units.
Phoenix
*
Posts: 44
Joined: 12 Mar 2016, 11:07
Location: UK

Re: SBBJT 0.1

Post by Phoenix »

Hey Johns1234

no worries on the code front :D I'm actually using the source code to teach myself a bit of C# and something I'll have an interest in instead of the standard Hello Worlds and real basics. Always found it easier to learn from real world scenarios.
Hope you don't mind but I started a branch to practice on. There was also a couple of bits I wanted to play around with which may be too customised for a central build:
  • One that I found after a quick search on ebay (for this and other projects) was a usb 8 relay card (£15). It uses the FTD2XX_NET dll to interface and a very basic byte stream. Long and short is you can switch up to a 10A 240V circuit with a response time of less than 0.1 second. As this may need to buffer (still need to play with the dll) what the states of the dll's are I was looking to implement a "Relay #" and "Time" into the event Actions.
  • Looking to do a simple Arduino with 2.8" (may do bigger) LCD screen to give a simple view of the current state. I found when testing that positioning of laptop and camera was not always conducive to viewing the screen. A small read out on a remote unit would help with this
I've managed to so far add a VeryDT region, % of DT setting, VDT events, camera exspossure, removing punishment count from session length caluclation.
I also started to look at using an XML file instead of a settings.ini file with the potential preprogrammed sessions idea in mind. Only just starting to use Linq and I'll admit I haven't got it working at all yet. No idea if it'd be useful or not but code I've currently got is here:

Code: Select all

using System;
using System.Collections.Generic;
using System.Xml.Linq;
using System.Linq;



namespace SBBJT
{
    class XMLSettings
    {

        public class BJSession
        {
            public string Name { get; set; }
            public string Password { get; set; }
            public string Description { get; set; }
            public int StartDelay { get; set; }
            public int ReleaseTime { get; set; }
            public int ReleaseTimeMax { get; set; }
            public bool ShowTimer { get; set; }
            public int SessionTimeMax { get; set; }
            public int SessionCancelAfterXConsecutiveFails { get; set; }
            public string ReleaseProgram { get; set; }
            public string ReleaseProgramParameters { get; set; }
            public bool TimedCaptureEnabled { get; set; }
            public int TimedCaptureInterval { get; set; }
            public string CaptureDirectory { get; set; }
            public string AudioDirectory { get; set; }
            public List<CameraSettings> Camera = new List<CameraSettings>();
            public List<JobSettings> Job = new List<JobSettings>();
        }
        
        public class CameraSettings
        {
            public string Name { get; set; }
            public string Resolution { get; set; }
            public string Threshold { get; set; }

        }

        public class JobSettings
        {
            public int ID { get; set; }
            public string Description { get; set; }
            public List<RegionsClass> Regions = new List<RegionsClass>();
            public List<SucksClass> Sucks = new List<SucksClass>();
            public List<DTClass> DT = new List<DTClass>();
            public List<RespiteClass> Respite = new List<RespiteClass>();
            public List<EventActionsClass> EventActions = new List<EventActionsClass>();

        }

        public class RegionsClass
        {
            
            public List<RegionClass> Region = new List<RegionClass>();

        }

        public class RegionClass
        {

            public int ID { get; set; }
            public string Name { get; set; }
            public int X { get; set; }
            public int Y { get; set; }
            public int Height { get; set; }
            public int Width { get; set; }

        }

        public class SucksClass
        {

            public int Min { get; set; }
            public int Max { get; set; }
            public bool Randomise { get; set; }
            public int SpeedMin { get; set; }
            public int SpeedMax { get; set; }
            public bool SpeedRandomise { get; set; }
            public bool SpeedRampUp { get; set; }
            public int SpeedRampUpReversal { get; set; }
            public decimal Wait { get; set; }
            public bool HeadMustStayInMouth { get; set; }
            public bool AllowHeadPlay { get; set; }
            public bool CheatCheck { get; set; }
            public bool FailedTriggersDT { get; set; }
            public int FailedAddsX { get; set; }
            public int FailedAddsXReleaseTime { get; set; }

        }

        public class DTClass
        {

            public int DTRandomChance { get; set; }
            public int DTAtLeastOneInX { get; set; }
            public int DTAtLastX { get; set; }
            public int DTHoldTimeMin { get; set; }
            public int DTHoldTimeMax { get; set; }
            public bool DTHoldTimeRandomise { get; set; }
            public int RewardDTReduceSucksByX { get; set; }
            public int RewardConsecutiveDTCount { get; set; }
            public int RewardConsecutiveDTReduceSucksByX { get; set; }
            public int RewardHeldDTReduceSucksByXPerSecondHeld { get; set; }
            public bool FailedDTTriggersDT { get; set; }
            public int FailedDTAddsXSucks { get; set; }
            public int FailedDTAddsXReleaseTime { get; set; }

        }

        public class RespiteClass
        {

            public bool Enabled { get; set; }
            public int RestTime { get; set; }
            public int ConsecutiveWithoutFail { get; set; }
            public int SucksPerMinute { get; set; }
            public int SucksPerMinuteAllowedFailRate { get; set; }

        }

        public class EventActionsClass
        {

            public List<EventActionClass> Event = new List<EventActionClass>();

        }

        public class EventActionClass
        {
            public string Name { get; set; }
            public bool CaptureImage { get; set; }
            public int RandomChance { get; set; }
            public string Program { get; set; }
            public string ProgramArguments { get; set; }

        }

        public List<BJSession> GetSessionList()
        {
            XElement xmlDoc = XElement.Load("ExampleSession.xml");
            var Sessions = from sess in xmlDoc.Descendants("Session")
        
                select new BJSession
                {
                    Name = sess.Element("Name").Value,
                    Password = sess.Element("Password").Value,
                    Description = sess.Element("Description").Value,
                    StartDelay = Convert.ToInt16(sess.Element("StartDelay").Value),
                    ReleaseTime = Convert.ToInt16(sess.Element("ReleaseTime").Value),
                    ReleaseTimeMax = Convert.ToInt16(sess.Element("ReleaseTime").Value),
                    ShowTimer = Convert.ToBoolean(sess.Element("ShowTimer").Value),
                    SessionTimeMax = Convert.ToInt16(sess.Element("SessionTimeMax").Value),
                    SessionCancelAfterXConsecutiveFails = Convert.ToInt16(sess.Element("SessionCancelAfterXConsecutiveFails").Value),
                    ReleaseProgram = sess.Element("ReleaseProgram").Value,
                    ReleaseProgramParameters = sess.Element("ReleaseProgramParameters").Value,
                    TimedCaptureEnabled = Convert.ToBoolean(sess.Element("TimedCaptureEnabled").Value),
                    TimedCaptureInterval = Convert.ToInt16(sess.Element("TimedCaptureInterval").Value),
                    CaptureDirectory = sess.Element("CaptureDirectory").Value,
                    AudioDirectory = sess.Element("AudioDirectory").Value,

                    Camera = new List<CameraSettings>(from cmra in sess.Descendants("Camera")
                        select new CameraSettings
                        {
                            Name = cmra.Element("Name").Value,
                            Resolution = cmra.Element("Resolution").Value
                        }).ToList(),
                    
                    Job = new List<JobSettings>(from jb in sess.Descendants("Job")
                        select new JobSettings
                        {
                            ID = Convert.ToInt16(jb.Element("ID").Value),
                            Description = jb.Element("Description").Value,
                            Regions = new List<RegionsClass>(from regionz in jb.Descendants("Regions")
                                select new RegionsClass
                                {

                                }).ToList(),
                            Sucks = new List<SucksClass>(from suckz in jb.Descendants("Sucks")
                                select new SucksClass
                                {
                                    Min = Convert.ToInt16(suckz.Element("Min").Value),
                                    Max = Convert.ToInt16(suckz.Element("Max").Value),
                                    Randomise = Convert.ToBoolean(suckz.Element("Randomise").Value),
                                    SpeedMin = Convert.ToInt16(suckz.Element("SpeedMin").Value),
                                    SpeedMax = Convert.ToInt16(suckz.Element("SpeedMax").Value),
                                    SpeedRandomise = Convert.ToBoolean(suckz.Element("SpeedRandomise").Value),
                                    SpeedRampUp = Convert.ToBoolean(suckz.Element("SpeedRampUp").Value),
                                    SpeedRampUpReversal = Convert.ToInt16(suckz.Element("SpeedRampUpReversal").Value),
                                    Wait = Convert.ToDecimal(suckz.Element("Wait").Value),
                                    HeadMustStayInMouth = Convert.ToBoolean(suckz.Element("HeadMustStayInMouth").Value),
                                    AllowHeadPlay = Convert.ToBoolean(suckz.Element("AllowHeadPlay").Value),
                                    CheatCheck = Convert.ToBoolean(suckz.Element("CheatCheck").Value),
                                    FailedTriggersDT = Convert.ToBoolean(suckz.Element("FailedTriggersDT").Value),
                                    FailedAddsX = Convert.ToInt16(suckz.Element("FailedAddsX").Value),
                                    FailedAddsXReleaseTime = Convert.ToInt16(suckz.Element("FailedAddsXReleaseTime").Value),
                                }).ToList(),
                            DT = new List<DTClass>(from DTz in jb.Descendants("DT")
                                select new DTClass
                                {
                                    DTRandomChance = Convert.ToInt16(DTz.Element("DTRandomChance").Value),
                                    DTAtLeastOneInX = Convert.ToInt16(DTz.Element("DTAtLeastOneInX").Value),
                                    DTAtLastX = Convert.ToInt16(DTz.Element("DTAtLastX").Value),
                                    DTHoldTimeMin = Convert.ToInt16(DTz.Element("DTHoldTimeMin").Value),
                                    DTHoldTimeMax = Convert.ToInt16(DTz.Element("DTHoldTimeMax").Value),
                                    DTHoldTimeRandomise = Convert.ToBoolean(DTz.Element("DTHoldTimeRandomise").Value),
                                    RewardDTReduceSucksByX = Convert.ToInt16(DTz.Element("RewardDTReduceSucksByX").Value),
                                    RewardConsecutiveDTCount = Convert.ToInt16(DTz.Element("RewardConsecutiveDTCount").Value),
                                    RewardConsecutiveDTReduceSucksByX = Convert.ToInt16(DTz.Element("RewardConsecutiveDTReduceSucksByX").Value),
                                    RewardHeldDTReduceSucksByXPerSecondHeld = Convert.ToInt16(DTz.Element(" RewardHeldDTReduceSucksByXPerSecondHeld").Value),
                                    FailedDTTriggersDT = Convert.ToBoolean(DTz.Element("FailedDTTriggersDT").Value),
                                    FailedDTAddsXSucks = Convert.ToInt16(DTz.Element("FailedDTAddsXSucks").Value),
                                    FailedDTAddsXReleaseTime = Convert.ToInt16(DTz.Element("FailedDTAddsXReleaseTime").Value)

                                }).ToList(),
                            Respite = new List<RespiteClass>(from respitez in jb.Descendants("Respite")
                                select new RespiteClass
                                {
                                    Enabled = Convert.ToBoolean(respitez.Element("Enabled").Value),
                                    RestTime = Convert.ToInt16(respitez.Element("RestTime").Value),
                                    ConsecutiveWithoutFail = Convert.ToInt16(respitez.Element("ConsecutiveWithoutFail").Value),
                                    SucksPerMinute = Convert.ToInt16(respitez.Element("SucksPerMinute").Value),
                                    SucksPerMinuteAllowedFailRate = Convert.ToInt16(respitez.Element("SucksPerMinuteAllowedFailRate").Value)

                                }).ToList(),
                            EventActions = new List<EventActionsClass>(from eventActs in jb.Descendants("EventActions")
                                select new EventActionsClass
                                {
                                    Event = new List<EventActionClass>(from eventAct in eventActs.Descendants("Event")
                                        select new EventActionClass
                                        {
                                            Name = eventAct.Element("Name").Value,
                                            CaptureImage = Convert.ToBoolean(eventAct.Element("CaptureImage").Value),
                                            RandomChance = Convert.ToInt16(eventAct.Element("RandomChance").Value),
                                            Program = eventAct.Element("Program").Value,
                                            ProgramArguments = eventAct.Element("ProgramArguments").Value

                                        }).ToList()
                                }).ToList()
                        }).ToList()

                };
                return Sessions.ToList();
        }
    }
}
Sample XML

Code: Select all

<?xml version>"1.0" encoding>"utf-8"?>
<Session xmlns:xsi>"http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd>"http://www.w3.org/2001/XMLSchema">
  <Name>Session Name</Name>
  <Password>Password01</Password>
  <Description>A Description</Description>
  <StartDelay>0</StartDelay>
  <ReleaseTime>1</ReleaseTime>
  <ReleaseTimeMax>60</ReleaseTimeMax>
  <ShowTimer>True</ShowTimer>
  <SessionTimeMax>120</SessionTimeMax>
  <SessionCancelAfterXConsecutiveFails>30</SessionCancelAfterXConsecutiveFails>
  <ReleaseProgram></ReleaseProgram>
  <ReleaseProgramParameters></ReleaseProgramParameters>
  <TimedCaptureEnabled>False</TimedCaptureEnabled>
  <TimedCaptureInterval>2</TimedCaptureInterval>
  <CaptureDirectory>capture</CaptureDirectory>
  <AudioDirectory>audio</AudioDirectory>
  <Camera>
    <Name></Name>
    <Resolution></Resolution>
    <Threshold></Threshold>
  </Camera>  
  <Job>
    <ID>1</ID>
    <Description></Description>
    <Region>
       <ID>1</ID>
       <Name>H</Name>
       <X></X>
       <Y></Y>
       <Height></Height>
       <Width></Width>
    </Region>
    <Region>
       <ID>2</ID>
       <Name>S</Name>
       <X></X>
       <Y></Y>
       <Height></Height>
       <Width></Width>
    </Region>
    <Region>
       <ID>3</ID>
       <Name>D</Name>
       <X></X>
       <Y></Y>
       <Height></Height>
       <Width></Width>
    </Region>
    <Region>
       <ID>4</ID>
       <Name>XD</Name>
       <X></X>
       <Y></Y>
       <Height></Height>
       <Width></Width>
    </Region>
    <Sucks>
       <Min>100</SMin>
       <Max>200</SMax>
       <Randomize>False</SRandomize>
       <SpeedMin>2</SpeedMin>
       <SpeedMax>6</SpeedMax>
       <SpeedRandomize>False</SpeedRandomize>
       <SpeedRampUp>True</SpeedRampUp>
       <SpeedRampUpReversal>90</SpeedRampUpReversal>
       <Wait>0.5</Wait>
       <HeadMustStayInMouth>True</HeadMustStayInMouth>
       <AllowHPlay>True</AllowHPlay>
       <CheatCheck>False</CheatCheck>
       <FailedTriggersDT>False</FailedTriggersDT>
       <FailedAddsX>2</FailedAddsX>
       <FailedAddsXReleaseTime>0</FailedAddsXReleaseTime>
    </Sucks>
    <DT>
       <DTRandomChance>50</DTRandomChance>
       <DTAtLeastOneInX>15</DTAtLeastOneInX>
       <DTAtLastX>5</DTAtLastX>
       <DTHoldTimeMin>2</DTHoldTimeMin>
       <DTHoldTimeMax>5</DTHoldTimeMax>
       <DTHoldTimeRandomize>True</DTHoldTimeRandomize>
       <RewardDTReduceSucksByX>1</RewardDTReduceSucksByX>
       <RewardConsecutiveDTCount>5</RewardConsecutiveDTCount>
       <RewardConsecutiveDTReduceSucksByX>5</RewardConsecutiveDTReduceSucksByX>
       <RewardHeldDTReduceSucksByXPerSecondHeld>1</RewardHeldDTReduceSucksByXPerSecondHeld>
       <FailedDTTriggersDT>False</FailedDTTriggersDT>
       <FailedDTAddsXSucks>2</FailedDTAddsXSucks>
       <FailedDTAddsXReleaseTime>0</FailedDTAddsXReleaseTime>
    </DT>
    <Respite>
       <Enabled>False</Enabled>
       <RestTime>60</RestTime>
       <ConsecutiveWithoutFail>40</ConsecutiveWithoutFail>
       <SucksPerMinute>30</SucksPerMinute>
       <SucksPerMinuteAllowedFailRate>10</SucksPerMinuteAllowedFailRate>
    </Respite>
    <EventActions>
       <Event>
          <Name>DeepThroatSuccessful</Name>
          <CaptureImage>True</CaptureImage>
          <RandomChance>100</RandomChance>
          <Program></Program>
          <ProgramArguments></<ProgramArguments>>
       </Event>
       <Event>
          <Name>Finished</Name>
          <CaptureImage>True</CaptureImage>
          <RandomChance>100</RandomChance>
          <Program></Program>
          <ProgramArguments></<ProgramArguments>>
       </Event>
    </EventActions>
  </Job>
    <Job>
      <ID>2</ID>
      <Description></Description>
      <Region>
         <ID>1</ID>
         <Name>H</Name>
         <X></X>
         <Y></Y>
         <Height></Height>
         <Width></Width>
      </Region>
      <Region>
         <ID>2</ID>
         <Name>S</Name>
         <X></X>
         <Y></Y>
         <Height></Height>
         <Width></Width>
      </Region>
      <Region>
         <ID>3</ID>
         <Name>D</Name>
         <X></X>
         <Y></Y>
         <Height></Height>
         <Width></Width>
      </Region>
      <Region>
         <ID>4</ID>
         <Name>XD</Name>
         <X></X>
         <Y></Y>
         <Height></Height>
         <Width></Width>
      </Region>
      <Sucks>
         <Min>100</SMin>
         <Max>200</SMax>
         <Randomize>False</SRandomize>
         <SpeedMin>2</SpeedMin>
         <SpeedMax>6</SpeedMax>
         <SpeedRandomize>False</SpeedRandomize>
         <SpeedRampUp>True</SpeedRampUp>
         <SpeedRampUpReversal>90</SpeedRampUpReversal>
         <Wait>0.5</Wait>
         <HeadMustStayInMouth>True</HeadMustStayInMouth>
         <AllowHPlay>True</AllowHPlay>
         <CheatCheck>False</CheatCheck>
         <FailedTriggersDT>False</FailedTriggersDT>
         <FailedAddsX>2</FailedAddsX>
         <FailedAddsXReleaseTime>0</FailedAddsXReleaseTime>
      </Sucks>
      <DT>
         <DTRandomChance>50</DTRandomChance>
         <DTAtLeastOneInX>15</DTAtLeastOneInX>
         <DTAtLastX>5</DTAtLastX>
         <DTHoldTimeMin>2</DTHoldTimeMin>
         <DTHoldTimeMax>5</DTHoldTimeMax>
         <DTHoldTimeRandomize>True</DTHoldTimeRandomize>
         <RewardDTReduceSucksByX>1</RewardDTReduceSucksByX>
         <RewardConsecutiveDTCount>5</RewardConsecutiveDTCount>
         <RewardConsecutiveDTReduceSucksByX>5</RewardConsecutiveDTReduceSucksByX>
         <RewardHeldDTReduceSucksByXPerSecondHeld>1</RewardHeldDTReduceSucksByXPerSecondHeld>
         <FailedDTTriggersDT>False</FailedDTTriggersDT>
         <FailedDTAddsXSucks>2</FailedDTAddsXSucks>
         <FailedDTAddsXReleaseTime>0</FailedDTAddsXReleaseTime>
      </DT>
      <Respite>
         <Enabled>False</Enabled>
         <RestTime>60</RestTime>
         <ConsecutiveWithoutFail>40</ConsecutiveWithoutFail>
         <SucksPerMinute>30</SucksPerMinute>
         <SucksPerMinuteAllowedFailRate>10</SucksPerMinuteAllowedFailRate>
      </Respite>
      <EventActions>
         <Event>
            <Name>DeepThroatSuccessful</Name>
            <CaptureImage>True</CaptureImage>
            <RandomChance>100</RandomChance>
            <Program></Program>
            <ProgramArguments></<ProgramArguments>>
         </Event>
         <Event>
            <Name>Finished</Name>
            <CaptureImage>True</CaptureImage>
            <RandomChance>100</RandomChance>
            <Program></Program>
            <ProgramArguments></<ProgramArguments>>
         </Event>
      </EventActions>
  </Job>
</Session>
Happy to share code I've got if it'd help at all

I've found a few more bugs for the list as well:
  • If you hit "Set Colours" mid session then it reenables the Start Session button. I've found mid session that I've sometimes needed to recalibrate the colour setting due to time of day, lighting and restrictions on the laptop camera.
  • Definately need a configurable "Exposure" setting for the camera. Got a new usb HD webcam and was finding the image was massively overexposed. Didn't find this one too difficult to implement
  • If you are doing a random # of Sucks in a session then you can easily reach the "Maximum" prior to the normal finish if you've had a couple of punishments handed out. Can understand this as a safety feature but this could also be done as maximum penalties possible to add can be ##% of the session value.
  • Several of the labels in Settings 2 have words beyond the bounds of the label

Ideas:
  • From Readme: Respite for having X sucks per minute with a failure rate less than Y% does not work yet. (The settings are there, but I did not get to implement them)
    I've been trying to think of ways to implement this and the only idea I could come up with is a stack recording the last X minutes. Chop off items once they surpasse a point and then interegate the stack for statistics.
    That being said with the other respite features is this actually needed?
  • On possible multiple BJs in a session I was thinking of having the suck and DT regions potentially move between BJs (a small amount 1-2 clicks worth) to bring some randomness into it. Could be done if implementing the XML settings
[*]I quite like the idea of being able to choose the last 5-10 sucks of a session and dictate them to be sucks of DT's. I know already have the last X as DT but thought this could be a nice "event" item to add. Can also then trigger sounds and other "Outputs" as well :)


I really like the report card idea!!
Be quite fun to have it presented almost like a school grading sheet with a grade A+,A,B,C,D etc at the top in red ink, rate different sections for suck and DT and even do a couple of the snapshots from the session as "Polaroid" pics at the bottom.

Again happy to help if you'd like and will be more than willing to provide more Testing feedback.

Phoenix
johns1234
*
Posts: 45
Joined: 22 Dec 2015, 01:32

Re: SBBJT 0.1

Post by johns1234 »

That is pretty impressive what you did there. I am glad someone picked up on my initial work and improves and adds to it.
Maybe we need somewhere a source code management ;)
Watch3r
*
Posts: 1
Joined: 30 Mar 2013, 17:43

Re: SBBJT 0.1

Post by Watch3r »

I do like the custom events. Thank you!
jerimy miles
*
Posts: 6
Joined: 16 Dec 2013, 07:38

Re: SBBJT 0.1

Post by jerimy miles »

great job, thanks much.

how about add sucks if the rule 'Head must stay in mouth' is broken and
the head is not covered ?
Phoenix
*
Posts: 44
Joined: 12 Mar 2016, 11:07
Location: UK

Re: SBBJT 0.1

Post by Phoenix »

sorry not been on the forum in a while as been down with a nasty bug.

Could well be an idea for a source control. I know GitHub has the following in it's T's & C's:
We may, but have no obligation to, remove Content and Accounts containing Content that we determine in our sole discretion are unlawful, offensive, threatening, libelous, defamatory, pornographic, obscene or otherwise objectionable or violates any party's intellectual property or these Terms of Service.
but may still be usable. Thoughts? Know of any that may be more accomodating to the content?

Going to start working on a 0.2 with as many of the features as possible implemented. Can always keep a running zip going if needs.

Wondering if the custom events needs expanding to have an Add +/- X Sucks, Trigger Suck/DT/Very DT/Respite option?
boundtocum
*
Posts: 12
Joined: 17 May 2015, 10:31

Re: SBBJT 0.1

Post by boundtocum »

Phoenix wrote: Wondering if the custom events needs expanding to have an Add +/- X Sucks, Trigger Suck/DT/Very DT/Respite option?
That could be down right nasty/evil. So I say ya, it's needed.

Like johns1234 said:
DeepThroatHeld - You held for over a second past the minimum time.
[Example: This is an evil spot for a punishment, you will earn X
sucks reduced when you hold longer, but maybe 20% of the time you
try you get shocked]
Make that a 20% chance to add a few sucks, or very very evil, make it add 3-4 DT before going back to your normal sucks.
Tenderfoot88
***
Posts: 458
Joined: 17 Sep 2013, 08:00
Location: British Columbia, Canada

Re: SBBJT 0.1

Post by Tenderfoot88 »

What features are you looking for in open source work? They're not specifically intended for such purposes, but Dropbox and GoogleDocs both allow sharing and collaboration in some form. I don't know about GoogleDocs, but I know Dropbox keeps a version history of files for every time it's edited.

Also, as far as I know, both companies have strict policies about your content being exclusively you're own business. (Can you imagine how hard they'd fall if Google tried to implement an anti-porn rule? The search engine is still their bread and butter, and I don't think you want to cut out that much of your potential market.)
Phoenix
*
Posts: 44
Joined: 12 Mar 2016, 11:07
Location: UK

Re: SBBJT 0.1

Post by Phoenix »

Tenderfoot88:
I think the key would be easy source control with labelling and ideally Visual Studio tie in. GitHub does all of these things out of the box which is why it's such an attractive option. The main thing would be to allow collaborative work. Johns1234 wrote the original program but I've since rewritten large chunks for V0.2. Being able to access each others updates would be useful.

Boundtocum:
I look at adding it in to 0.2 or 0.3 :wink:

The 20% is easy enough to do with the current implementation.
There's an event for "DeepThroatHeld", set the % at 20% and the program execution to your estim / the switchable plug with your estim on.
You could trigger an additional DT/VDT along with that. Triggering multiples isn't currently possible as the triggers are boolean but could be a future implementation to make them integers.
I am looking to add an internal link to a usb relay board (prob in 0.3) that will allow switching on / off / sequencing relays with the custom events. As these board are <£15 on ebay they could be used for switching an estim machine punishment.
oni
*
Posts: 9
Joined: 01 Feb 2015, 11:38

Re: SBBJT 0.1

Post by oni »

Phoenix wrote:Tenderfoot88:
I think the key would be easy source control with labelling and ideally Visual Studio tie in. GitHub does all of these things out of the box which is why it's such an attractive option. The main thing would be to allow collaborative work. Johns1234 wrote the original program but I've since rewritten large chunks for V0.2. Being able to access each others updates would be useful.
Using git is the best solution.

The SBBJv2 source is hosted on GitLab as a private repository and hasn't had any problems that I know of.
Both private and public repositories are free on GitLab.
Phoenix
*
Posts: 44
Joined: 12 Mar 2016, 11:07
Location: UK

Re: SBBJT 0.1

Post by Phoenix »

Cheers Oni

I'll take a look into setting one up. Just finished the code for multiple "jobs" and done a quick test. Still got the UI for it sort out but the core codes done. Also trying to get things camera resolution independent for easy sharing of configurations. Should be good :)
Post Reply