Pim_gd's Mods - DialogueActions v4.08 (15 Jan 2017) (2 Viewers)

DrZombi

Content Creator
Joined
Jul 10, 2016
I have just re-run my test dialogue with the new DA, with and without DP and it does not work. I'm still looping into the "now equals 60" while the actual value decreases. Exactly as if the "check" were directly checking the value of the variable (the last value actively set in dialogue) instead of calling the get() function to retrieve the value from SDT.
 

Pim_gd

Content Creator
Joined
Jan 25, 2013
I have just re-run my test dialogue with the new DA, with and without DP and it does not work. I'm still looping into the "now equals 60" while the actual value decreases. Exactly as if the "check" were directly checking the value of the variable (the last value actively set in dialogue) instead of calling the get() function to retrieve the value from SDT.

That's because you're writing a read-only variable. Don't do that. The moment you do {"set":{"mt.cuminmouth":60}} you have broken that variable.

What does it mean, if you have a local variable with the same name as a system variable? What scope should the variable value be pulled from? Right now, I opt for local scope for checks and system scope for variables. Preferring system scope can be done, but I think it's wrong to set a read-only variable in the first place.

Pim_gd / SDTDialogueActions / commit / c96f6fe59ccd — Bitbucket

Of interest is this line:

Code:
if (!g.dialogueControl.advancedController._dialogueDataStore.hasOwnProperty(variableName))

It means "if there is no local variable with this name".
 
Last edited:

sby

Content Creator
Coder
Joined
Sep 11, 2012
I'd rather not integrate the code. It has its hooks in too many functionalities, and I don't fully understand how it works.

My proposed fix: ( sby sby DrZombi DrZombi )

Dialogpatch changes the proxy for canPlay to use mycanplay.

Code:
        var canPlayProx:Object = lProxy.createProxy(g.dialogueControl.advancedController, "canPlay");
        canPlayProx.addPre(canPlay, persist==1);
        canPlayProx.hooked = false;

to

Code:
        var canPlayProx:Object = lProxy.createProxy(g.dialogueControl.advancedController, "canPlay");
        canPlayProx.addPre(mycanPlay, persist==1);
        canPlayProx.hooked = false;

Dialogpatch calls canPlay instead of mycanPlay for sayRandomPhrase.

Code:
            for each (_loc_5 in _loc_3)
            {
                if (mycanPlay(_loc_5))    //don't use object's canplay, use my custom one (which also calls my custom controller canplay)
                {
                    _loc_4.push(_loc_5);
                }
            }

to

Code:
            for each (_loc_5 in _loc_3)
            {
                if (g.dialogueControl.advancedController.canPlay(_loc_5))
                {
                    _loc_4.push(_loc_5);
                }
            }

These two changes make it so that there's only one execution flow for checking the eligibility of a line.

DialogueActions hooks canPlay after DialogPatch.

That is, g.dialogueControl.advancedController.canPlay_l calls DA.canPlay calls DP.mycanPlay calls DP.canPlay.

DialogueActions adds a post listener for canPlay.

In the hook for canPlay, DialogueActions fills any requested variables in the dict if not present.

In the post listener for canPlay, DialogueActions removes any variables it has filled in.

I have attached a build with check functional. If the changes I suggested are made, and the load order is Dialogpatch and after that DialogueActions, everything should work fine, from what I'm seeing.

Here's a commit to show what I changed:

Pim_gd / SDTDialogueActions / commit / c96f6fe59ccd — Bitbucket

Dialogues used for testing:

Code:
start:"checking to see if we can check *da.breathPercentage* [line]"

line:"breathpercentage 100![line]" {"check":{"da.breathPercentage":100}}
line:"no check used![line]"

Code:
start:"checking to see if we can check *da.breathPercentage* [line]"

line:"breathpercentage 100![line]" {"check":{"da.breathPercentag":100}}
line:"no check used![line]"

The first one spams both lines, the second one only spams one line.

made some changes to dialogpatch for people to try out, just changed that direct call to my function to instead go through proxies


there is a advanced controller canplay, and a line canplay. the mycanplay is used to replace the line canplay, which i believe you cannot proxy because they are created on the fly as needed. this is still directly referenced in the sayrandomphrase function that is proxied.
i changed the direct canplay reference to the advanced controller function, which should then trigger the proxy i and DA will have.
 

Attachments

@@-dialogpatchV4.zip
297.1 KB · Views: 143

DrZombi

Content Creator
Joined
Jul 10, 2016
That's because you're writing a read-only variable. Don't do that. The moment you do {"set":{"mt.cuminmouth":60}} you have broken that variable.

I'm sorry but I don't understand. Why do you say that the variable is read only ? I did declare it as read & write:

Code:
registerVarRead("mt.cuminmouth", getCumInMouth, this, []);
            registerVarWrite("mt.cuminmouth", setCumInMouth, this, []);
            registerVarRead("mt.vigour", getVigour, this, []);
            registerVarWrite("mt.vigour", setVigour, this, []);

I can set it and it works and the game don't bother, the cum is added in the mouth with no problem and then it decreases as she swallows so I can't see anything broken ? (And the variable itself is still updated well since I can retrieve it through *mt.cuminmouth*. It's only the check which thinks that it's a local value. And I understand how doing the set could "create" a local variable but I don't get why my variable would be read only in the first place... Could you give me a little more details please ? I don't know the dialogue system as well as you do !

What does it mean, if you have a local variable with the same name as a system variable? What scope should the variable value be pulled from? Right now, I opt for local scope for checks and system scope for variables. Preferring system scope can be done, but I think it's wrong to set a read-only variable in the first place.

Pim_gd / SDTDialogueActions / commit / c96f6fe59ccd — Bitbucket

Of interest is this line:

Code:
if (!g.dialogueControl.advancedController._dialogueDataStore.hasOwnProperty(variableName))

It means "if there is no local variable with this name".

So I assume that changing the name of my variable (to something like mt.cim for example) will change nothing since it will be 100% local then ?

[EDIT]: And if I try to remove the "set" line, I have the same problem as before with the variable's value being "undefined". So I don't understand why you are able to check on da.breathPercentage for example...

[EDIT]: I can't see the difference with what you did yourself:

Code:
v.registerVariableRead("da.breathPercentage", new FunctionObject(getHerBreathPercentage, this, []));
v.registerVariableWrite("da.breathPercentage", new FunctionObject(setHerBreathPercentage, this, []));

Is it really a name problem ? Should I rename the variable ? I'll try and see...

[EDIT]: Tried to rename the variable to mt.cuminmouthPercentage but this changes nothing. I really can't see the difference between my variable and yours...
 
Last edited:

Pim_gd

Content Creator
Joined
Jan 25, 2013
Code:
initial_settings:{"counter":0,"changed":0}

start:"checking to see if we can check *da.clothes.panties.type* [line]"

line:"[SETVAR_counter_+=1]Briefs![line]" {"check":{"da.clothes.panties.type":"Briefs"}}
line:"[SETVAR_counter_+=1]no panties![line]" {"check":{"da.clothes.panties.type":"None"}}
line:"[SETVAR_counter_+=1]no check![line]"
line:"Setting panties to briefs![SETVAR_da.clothes.panties.type_Briefs][line]" {"set":{"changed":1},"check":{"changed":0,"counter":">5"}}

This dialogue works for me.

I'll trace the code path to see if there's something that can go wrong...

Code:
var onVariableWriteProxy:Object = lProxy.createProxy(g.dialogueControl.advancedController, "setValues");
            onVariableWriteProxy.addPre(onVariableWrite, persist);
            onVariableWriteProxy.hooked = false;

Code:
        public function onVariableWrite(args:*) {
            //displayMessageGreen("onVariableWrite");
            var x = variableManager.variableWrite(args);
            if (x != undefined) {
                return x;
            }
        }

Code:
        //Replaces SDT's g.dialogueControl.advancedController.setValues, used for setting values in the "set" line-attribute.
        public function variableWrite(variables:*) {
            var varname:* = null;
            var value:* = null;
           
            for (varname in variables) {
                var copyValue:Boolean = false;
                //g.dialogueControl.advancedController.outputLog("Variable " + varname + " found");
                //g.dialogueControl.advancedController.outputLog("rest" + variables);
                value = variables[varname];
                var result:* = setVariableValue(varname, value);//check for handlers
                if (result != undefined) {
                    continue;
                }
                if (hasGlobalVariable(varname)) {
                    copyValue = globalVariables[varname].isAttached();
                }
                var oldValue:* = null;
                if (g.dialogueControl.advancedController._dialogueDataStore.hasOwnProperty(varname)) {
                    oldValue = g.dialogueControl.advancedController._dialogueDataStore[varname];
                }

Key in this third snippet is that "setVariableValue" MUST return something, else the variable will be set into the dictionary and you'll be fucked from there on.

Code:
        public function setVariableValue(name:String, value:*):* {
            if (registeredVariablesSet.hasOwnProperty(name)) {
                return registeredVariablesSet[name].call(value);
            }
        }

For clothing...

Code:
        public function setClothesName(clothType:String, value:*):int {
            var clothObject:Object = getClothObject(clothType);
            var index:int = clothObject.elementNameList.indexOf(value);
            if (index != -1) {
                clothObject.selection = index;
                if(clothObject.associatedModType)
                {
                    g.customElementLoader.clearModTypes([clothObject.associatedModType]);
                }
                clothObject.resetElement();
            } else {
                m.displayMessageRed("Can't find clothing piece (" + value + ") for " + clothType);
            }
           
            return clothObject.selection;
        }

it returns something...

for breathpercentage...

Code:
        public function setHerBreathPercentage(value:*):void {
            var newVal:Number = 0;
            if (value is Number) {
                newVal = 100 - value;
                newVal = Math.min(newVal, 100);
                newVal = Math.max(newVal, 0);
            } else if (value is String && !isNaN(Number(value))) {
                var currentVal:Number = getHerBreathPercentage();
                if ((value as String).charAt(0) == "-" || (value as String).charAt(0) == "+" ){
                    newVal = currentVal - Number(value);//It's inverted. Goes from 0 to max instead from max to 0.
                } else {
                    newVal = Number(value);
                }
                newVal = Math.min(newVal, 100);
                newVal = Math.max(newVal, 0);
            } else {
                m.displayMessageRed("da.breathPercentage attempted set to " + value + ", unable to identify value as numeric");
                return;
            }
            g.currentBreathLevel = (g.breathLevelMax / 100) * newVal;
        }

it doesn't.

So if I run this dialogue...

Code:
initial_settings:{"counter":0,"changed":0}

start:"checking to see if we can check *da.breathPercentage* [line]"

line:"[SETVAR_counter_+=1]100![line]" {"check":{"da.breathPercentage":100}}
line:"[SETVAR_counter_+=1]less than 99![line]" {"check":{"da.breathPercentage":"<99"}}
line:"[SETVAR_counter_+=1]no check![line]"
line:"Setting breath to 5![SETVAR_da.breathPercentage_5][line]" {"set":{"changed":1},"check":{"changed":0,"counter":">5"}}

it stops working:
Code:
891: Running checks for line: "[SETVAR_counter_+=1]100![line]"
892:    Line will not play: "da.breathPercentage" needs to be 100 but is currently set to 5

DrZombi DrZombi hmm, now what? I don't think a function should have to return a value... ... I think it's a bug, I'll fix it. After lunch.
 

Pim_gd

Content Creator
Joined
Jan 25, 2013
So I checked my source archives, and this bug was present in v2.00 - since 2014. So, from what I can see, I wrote it like this because... well, I don't know. Presumably, the effect is to be able to say "I don't know what to do with this variable, so ... let SDT handle it." But that's a useless thing to say or do, because, well, how is DialogueActions supposed to know whether a variable value should just be set in the local scope?

About scopes
There are 4 scopes. I've used the terms "local scope" and "global scope" before when explaining local and global variables, so I'll try to use the same terms here. There is a local scope, a global scope, a system scope (to refer to the "system variable" I named earlier) and a save scope. This is from the perspective of DialogueActions; if you were writing a dialogue, you'd tend to talk more about local, global and "da scope".

The local scope consists of variables defined in initial_settings. The local scope is stored in g.dialogueControl.advancedController._dialogueDataStore.
The global scope consists of variables that have been created via [DEFINEGLOBALS_...] and related triggers. They exist in DialogueActions - variableManager.globalVariables to be precise.
The system or mod variable scope are all variables that don't really "exist" but are defined as special keywords for DA to hook on. That's stuff like da.breathPercentage or mt.cuminmouth. These exist in DA's variableManager.registeredVariablesSet and variableManager.registeredVariablesGet
The save scope are the variables stored in a savefile. Those'll be in some SharedObjects folder in your filesystem.

When using SETVAR or the set line-attribute
When you write to a variable, normally, the variable and value are stored in local scope. DialogueActions may interfere; if the variable resides in system scope, the variable will not be set in the local scope. This is where the bug is at the moment; this doesn't happen in cases where the function called doesn't return a value. If the variable doesn't exist in system scope but does exist in global scope, and the variable is currently linked, any writes will be copied over to the variable in global scope - thus affecting both local and global scope.

When inserting via asterisks
I'm gonna ignore the so-called "Substitutions" (YOU/YOUR/ME/MY/FINISHES) in this section.
Without DialogueActions, the variable is inserted from local scope if found. With DialogueActions, the requested variable is split up based on spaces. Then each variable is checked to see if it contains operators (if so, that's an error ... somehow ... probably to stop my-variable from blowing things up). Then it goes into something I call a "StringQuation" which tries to treat the whole thing as a expression. Result is that you can do crap like *4 + 3*. Anyway, if a variable in a StringQuation is not found in system scope, it will try the local scope. That's important - insertions go system scope first, then local scope.

When using the check line-attribute
When using the check line-attribute, the local scope goes first. This because... I don't know... ... The best reason I can come up with is "to try and break the minimum possible". I don't plan on changing this because DialogPatch also changes the check mechanism. DialogPatch v4 should work with future DA versions.

Anyway, I have fixed the check line-attribute so that it properly identifies if a variable exists in system scope or not - see Pim_gd / SDTDialogueActions / commit / d25a8a30b3a1 — Bitbucket.

Here's a build to play with.
 

Attachments

SDTDialogueActions.swf
148.1 KB · Views: 164

DrZombi

Content Creator
Joined
Jul 10, 2016
I'm sorry to tell you that my test dialogue still does not work.

now the result of the check is always "undefined" and so I get any of the first 3 lines chosen randomly :eek:
At first, I thought that it was working because undefined seems to be treated like a 0 by the dialogue system and so I ended up when she has swallowed it all to a situation where only the "equals 0", "below 30" and "below 60" lines were chosen, which seemed to be good. But after a closer look, while the value is decreasing, I also have these 3 lines chosen randomly and then I noticed in the log that the value reported by the check is "undefined" :frown:

The test dialogue:

all:"CLEAR"

start:"[intro]mt.cuminmouth set to *mt.cuminmouth*..." {"style":"Thought","set":{"mt.cuminmouth":60}}

intro:"[intro]mt.cuminmouth now equals 0, cuminmouth%3A *mt.cuminmouth*" {"style":"Thought","check":{"mt.cuminmouth":0}}
intro:"[intro]mt.cuminmouth now below 30, cuminmouth%3A *mt.cuminmouth*" {"style":"Thought","check":{"mt.cuminmouth":"<30"}}
intro:"[intro]mt.cuminmouth now below 60, cuminmouth%3A *mt.cuminmouth*" {"style":"Thought","check":{"mt.cuminmouth":"<60"}}
intro:"[intro]mt.cuminmouth now equals 60, cuminmouth%3A *mt.cuminmouth*" {"style":"Thought","check":{"mt.cuminmouth":60}}
intro:"[intro]mt.cuminmouth now over 60, cuminmouth%3A *mt.cuminmouth*" {"style":"Thought","check":{"mt.cuminmouth":">60"}}


(I've tried with da.breathPercentage for the same results)

Any other idea ?
 

Pim_gd

Content Creator
Joined
Jan 25, 2013
So I added some debug lines and...

601: Running checks for line: "[SETVAR_counter_+=1]100![line]"
602: Line will not play: "da.breathPercentage" needs to be 100 but is currently set to undefined
603: proxyDialogueDict
604: proxyDialogueDict::da.breathPercentage noticed in check attribute
605: proxyDialogueDict::da.breathPercentage not found in local scope
606: proxyDialogueDict::da.breathPercentage added to local scope with value 100
607: unproxyDialogueDict
608: unproxyDialogueDict::da.breathPercentage removed from local scope

Hmmh, well, that's useless. Did I get the hooking wrong?

*changes load order*

595: proxyDialogueDict
596: proxyDialogueDict::da.breathPercentage noticed in check attribute
597: proxyDialogueDict::da.breathPercentage not found in local scope
598: proxyDialogueDict::da.breathPercentage added to local scope with value 100
599: Running checks for line: "[SETVAR_counter_+=1]100![line]"
600: Okay.
601: unproxyDialogueDict
602: unproxyDialogueDict::da.breathPercentage removed from local scope

Okay, so, DrZombi DrZombi I got the load order wrong, dialogpatch needs to go AFTER DialogueActions. But then it works.
 

DrZombi

Content Creator
Joined
Jul 10, 2016
Okay, so, DrZombi DrZombi I got the load order wrong, dialogpatch needs to go AFTER DialogueActions. But then it works.

OMG, I did not even tried that myself ! :eek:
*trying*
...
...
It works here too :smile:

So I think that now, you two could publish the new versions, they seem to work well together !
(I'll continue to test this new loading order with my previous dialogues to see if we did not break anything, and come back here if I find something).

Many thanks for your reactivity guys, you've corrected quickly a long time bug which was really a pain for a lot of writers I think !
 

sby

Content Creator
Coder
Joined
Sep 11, 2012
So I added some debug lines and...

601: Running checks for line: "[SETVAR_counter_+=1]100![line]"
602: Line will not play: "da.breathPercentage" needs to be 100 but is currently set to undefined
603: proxyDialogueDict
604: proxyDialogueDict::da.breathPercentage noticed in check attribute
605: proxyDialogueDict::da.breathPercentage not found in local scope
606: proxyDialogueDict::da.breathPercentage added to local scope with value 100
607: unproxyDialogueDict
608: unproxyDialogueDict::da.breathPercentage removed from local scope

Hmmh, well, that's useless. Did I get the hooking wrong?

*changes load order*

595: proxyDialogueDict
596: proxyDialogueDict::da.breathPercentage noticed in check attribute
597: proxyDialogueDict::da.breathPercentage not found in local scope
598: proxyDialogueDict::da.breathPercentage added to local scope with value 100
599: Running checks for line: "[SETVAR_counter_+=1]100![line]"
600: Okay.
601: unproxyDialogueDict
602: unproxyDialogueDict::da.breathPercentage removed from local scope

Okay, so, DrZombi DrZombi I got the load order wrong, dialogpatch needs to go AFTER DialogueActions. But then it works.
if you are going to be replacing the check proxy that the dialog patch does, just add in the ability to != feature (or copy and tweak it as needed) and do the proxy reset i posted before. also, if there is a way for dialogpatch to know that DA has been loaded before it, and if that version has the check proxy in it, then i could make it so it just doesn't do that proxy.
(like how i have an animtools_comm and a version number)

i forgot what happens if there are multiple pre proxies on the same function, perhaps the first one gets to return its value? i would have to look it up
 

DrZombi

Content Creator
Joined
Jul 10, 2016
also, if there is a way for dialogpatch to know that DA has been loaded before it

Yes you can, this is exactly what MoreTriggers does since it relies on DA's API. But I did borrow the code from Colin's Automation mod and I have to say that I don't really understand how it works. The part where it is supposed to detect the API does not make sense to me but it works so I leaved it like that, but I'm not sure that it would still work with another mod providing an API loaded.

, and if that version has the check proxy in it, then i could make it so it just doesn't do that proxy.
(like how i have an animtools_comm and a version number)

You 2 could rely on "lProxy.checkProxied(OBJECT, "FUNCTION_NAME");" for that one if you do not want to share a version variable. If the name of the function is well chosen to be sure that it is unique for DA, that could be enough.

i forgot what happens if there are multiple pre proxies on the same function, perhaps the first one gets to return its value? i would have to look it up

As per @ModGuy 's doc:

When writing these functions, be sure to remove the return type if it's not being used.
For example:

public function move(a:Number, b:Number):Number
public function move(a:Number, b:Number)

This is because Pre functions are called in order.
If the fist Pre returns a value and the second does not, we retain the first value.
We do this until we have looped through them all.
If we do not have a return value and the function is hooked, we call the original.
After this we store the return value if any then pass it to each Post function.
Finally, we return the value.


I think it means that there can be only one return value for all the Pre functions.
 

Jaxx

Content Creator
Joined
Aug 15, 2016
Hi Pim,
first, as it's the first time I talk to you, I'd like to thank you for DA which is an awesome mod and definitely changed the life of all dialog writters ! :grin:
I was thinking about a feature though I'm not sure it's you I should ask. The [MASTURBATE_ON] trigger and what happens next gave me the idea. As I discovered this mechanism in your mod, I assumed you could maybe do something about it, but you'll correct me if I'm wrong.
When she's masturbating and reaches climax, her pussy's dripping a bit right after she moans... would it be possible to make a trigger that call only this dripping ?
It would provide many possibilities for stories that writters think about.
The best would be to trigger the same animation than [DROOL] at her pussy but I have no idea if that's really possible.
I'm anxious to know what you can tell about all this :smile:
 
Last edited:

Pim_gd

Content Creator
Joined
Jan 25, 2013
See this code on Bitbucket
Code:
        public function tickCode():void {
            if (sTime > 0) {
                sTime--;
                var newDroplet:* = new Droplet(g.sceneLayer.globalToLocal(g.her.torso.backside.localToGlobal(new Point(30, 240))), new Point(Math.random() * 18 - 5, Math.random() * 25), Math.random() + 0.1, 0.01);
                newDroplet.padding = 2000;
                g.strandBackLayer.addChild(newDroplet);
            }  else {
                squirting = false;
            }
        }

Seems like it would be easy for someone to add a droplet spawner at that position.
 

Jaxx

Content Creator
Joined
Aug 15, 2016
Oh that's great Pim, I'll ask DrZombi if he agrees and know how to add something like that to moreTriggers because I'm not familiar at all with actionScript :frown:
 

DrZombi

Content Creator
Joined
Jul 10, 2016
Seems like it would be easy for someone to add a droplet spawner at that position.

Ah ah ! Seems we are in a situation of "snake who bites its own tail" since It's already me who spotted this code in DA and told Jaxx Jaxx to come to you :grin:

I told him because this part of DA is not exposed through the API and I thought it would be better integrated with the rest if we do not duplicate things like the squirting Boolean. But if you don't want to do it, I can copy paste the code for sure. Just thought it was not the best way to go.

By the way, since I'm here, do you know when you plan to release a new official version of DA with the "checks" corrected ? For what I've seen for now, it totally works with sby sby 's DialogPatchV4 (which is not released either, if you hear us) :smile:
 

sby

Content Creator
Coder
Joined
Sep 11, 2012
Pim_gd Pim_gd
how do we want to handle both mods wanting to proxy "canPlay" on g.dialogueControl.advancedController ?

right now, i have a check that prevents attempting to proxy it if dialogueactions api is up and canplay has been proxied. however, this is for the case where dialogue actions is loaded before the patch (which i doubt is going to be the load order)

i could add a check every frame to continue to see if this is the case, and remove its own proxy if found
 

sby

Content Creator
Coder
Joined
Sep 11, 2012

Attachments

@@-dialogpatchV4.zip
303.8 KB · Views: 153

Users who are viewing this thread

  • wesi
Top


Are you 18 or older?

This website requires you to be 18 years of age or older. Please verify your age to view the content, or click Exit to leave.