void JumpSafeToLocation(location lLoc)
{
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectCutsceneImmobilize(), OBJECT_SELF, 0.1);
ClearAllActions(TRUE);
JumpToLocation(lLoc);
ActionDoCommand(SetCommandable(TRUE));
SetCommandable(FALSE);
}
void JumpSafeToObject(object oObj)
{
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectCutsceneImmobilize(), OBJECT_SELF, 0.1);
ClearAllActions(TRUE);
JumpToObject(oObj);
ActionDoCommand(SetCommandable(TRUE));
SetCommandable(FALSE);
}
JumpSafeToLocation and JumpSafeToObject Functions
#1
Posté 08 février 2013 - 03:40
#2
Posté 08 février 2013 - 05:12
ClearAllActions and then JumpToObject or Location work fine for me.
#3
Posté 08 février 2013 - 08:26
Here's our most current function, ForceJump:
void ForceJump (object oTarget, location lTarget, int bClearCombat=TRUE, int bForceCommandable=FALSE) {
if (!GetIsObjectValid(oTarget) || GetObjectType(oTarget) != OBJECT_TYPE_CREATURE)
return;
if (!GetIsObjectValid(GetArea(oTarget))) {
DelayCommand(5.0, ForceJump(oTarget, lTarget, bClearCombat, bForceCommandable));
return;
}
if (GetIsDead(oTarget)) {
ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectResurrection(), oTarget);
ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectHeal(GetMaxHitPoints(oTarget)), oTarget);
effect eBad = GetFirstEffect(oTarget);
while (GetIsEffectValid(eBad)) {
if (GetEffectIsNegative(eBad))
RemoveEffect(oTarget, eBad);
eBad = GetNextEffect(oTarget);
}
if (GetIsPC(oTarget))
AssignCommand(oTarget, ExecuteScript("fky_deathprocess", oTarget));
DelayCommand(0.1, ForceJump(oTarget, lTarget, bClearCombat, bForceCommandable));
} else if (!GetCommandable(oTarget)) {
if (bForceCommandable) {
AssignCommand(oTarget, SetCommandable(TRUE));
if (bForceCommandable >= 5)
WriteTimestampedLogEntry("FORCEJUMP : " + GetPCPlayerName(oTarget) + " : " +
GetName(oTarget) + " : more than 5 attempts to force commandable jumping to " +
GetResRef(GetAreaFromLocation(lTarget)));
}
DelayCommand(1.0, ForceJump(oTarget, lTarget, bClearCombat, ++bForceCommandable));
} else {
AssignCommand(oTarget, ClearAllActions(bClearCombat));
AssignCommand(oTarget, ActionJumpToLocation(lTarget));
AssignCommand(oTarget, ActionDoCommand(SetCommandable(TRUE)));
AssignCommand(oTarget, SetCommandable(FALSE));
}
}
I'm aware that some of those things look a little strange, but I can assure you they're all there for a reason - many with a story behind them.
With regard to what I think your specific question is, the action queue stuff is there to prevent players from doing things that clear their queue to avoid the port.
Funky
Modifié par FunkySwerve, 08 février 2013 - 08:29 .
#4
Posté 08 février 2013 - 08:41
regarding this:
AssignCommand(oTarget, ClearAllActions(bClearCombat));
AssignCommand(oTarget, ActionJumpToLocation(lTarget));
AssignCommand(oTarget, ActionDoCommand(SetCommandable(TRUE)));
AssignCommand(oTarget, SetCommandable(FALSE));
Does the last assigned command execute first or only before either of the assigned actions?
Modifié par henesua, 08 février 2013 - 08:41 .
#5
Posté 08 février 2013 - 09:03
Oh, I should add that that function is mostly acaos', which is part of the reason I don't remember - he's the one that did most of the testing. I do know that it works perfectly, however, where CutSceneImmobilize had issues.
I see no indication of such in the Lexicon entry, either.
[Edit] I just read through them, sorry, working on a market-price-simulating algorithm and it's making me a bit spacy. They defeinitely execute in that order - the AssignCommand(SetCommandable(FALSE bit does NOT go on the action queue, which is why that order works.
Funky
Modifié par FunkySwerve, 08 février 2013 - 09:06 .
#6
Posté 08 février 2013 - 09:09
Thanks very much for sharing your new script - it's greatly appreciated.
Modifié par Thayan, 08 février 2013 - 10:36 .
#7
Posté 08 février 2013 - 09:15
That makes sense, and appears bomb proof.
I'll have to test whether it is possible to break:
ClearAllActions
JumpToObject/Location
I assumed nothing could sneak through that and haven't seen it happen, but I have had much less real world testing than you guys have had - only a few years for a small player base.
Thanks.
#8
Posté 08 février 2013 - 09:19
Why not execute the ForceJump on the target to be jumped?
It seems to me that you'd have one less object to pass, and could skip the check for a valid target.
#9
Posté 08 février 2013 - 09:22
[Edit] I think the != CREATURE check is also to prevent endless recursion, in the event that a dm accidentally clicks on a useable place when targeting a SIMTools command, but that was definitely acaos' addition, so I'm not positive.
Funky
Modifié par FunkySwerve, 08 février 2013 - 09:26 .
#10
Posté 08 février 2013 - 09:44
#11
Posté 08 février 2013 - 10:10
henesua wrote...
The reason I asked is because I assumed that ExecuteScript failed and exited when run on an invalid object.
Oh, sorry, I misread your question. We never AssignCommand it, so the thing being jumped isn't the thing running the script.. See, e.g.:
abo_eldest_death (43): DelayCommand(2.0, ForceJump(oPC, lJump));
abo_endcombat (195): ForceJump(oPC, lReturn);
abo_endcombat (759): ForceJump(oPC, GetLocation(oWay));
abo_portal_use (63): ForceJump(oPC, lTarget);
abo_trapboulder (10): DelayCommand(6.0, ForceJump (oPC, lTarget));
aby_boss_heart (334): ForceJump(oTarget, GetLocation(GetWaypointByTag("WorkShopHellStart")));
aby_boss_heart (395): ForceJump(oTarget, GetLocation(GetWaypointByTag("WorkShopHellStart")));
aby_boss_heart (495): ForceJump(oTarget, GetLocation(GetWaypointByTag("WorkShopHellStart")));
aby_boss_heart (628): ForceJump(oTarget, GetLocation(GetWaypointByTag("WorkShopHellStart")));
aby_death (269): ForceJump(oTarget, GetLocation(oWay));
aby_enter (1687): ForceJump(oPC, GetLocation(GetWaypointByTag("WorkShopHellStart")));
aby_portal_conv (110): ForceJump(oPC, lTarget);
aby_prince_port (12): ForceJump(oPC, GetLocation(GetWaypointByTag("aby_portal_pop0")));
aby_than_door (40): ForceJump(oPC, lTarget);
afx_deathcrown (324): ForceJump(oJump, lHGate);
antidoorgeneral (8): ForceJump(oPC, GetLocation(GetNearestObjectByTag("AntiDoorWay")));
antidoormoad (7): ForceJump(oPC, GetLocation(GetNearestObjectByTag("AntiDoorWay")));
antidoortomb (8): ForceJump(oPC, GetLocation(GetNearestObjectByTag("AntiDoorWay")));
antiexploitacade (20): ForceJump(oPC, GetLocation(GetNearestObjectByTag("funkywaypoint196")));
antiexploitlolth (10): ForceJump(oPC, GetLocation(GetNearestObjectByTag("funkywaypoint098")));
antiexploitmaze (10): ForceJump(oPC, GetLocation(GetNearestObjectByTag("funkywaypoint149")));
antiexploitmoad (9): ForceJump(oPC, GetLocation(GetNearestObjectByTag("funkywaypoint")));
antiexploitsactm (10): ForceJump(oPC, GetLocation(GetNearestObjectByTag("funkywaypoint150")));
antiexploitshrik (9): ForceJump(oPC, GetLocation(GetNearestObjectByTag("funkywaypoint113")));
antifencegeneral (7): ForceJump(oPC, GetLocation(GetNearestObjectByTag("AntiDoorWay")));
bvill_cellar_ent (18): if (!GetIsOwnerPresent()) ForceJump(oPC, GetLocation(GetWaypointByTag("BVillaUpstairsPort")));
ca_sd_step (85): ForceJump(oPC, GetLocation(oTarget));
deathstart (7): ForceJump(oPC, GetLocation(oDrop));
ele_portal_conv (27): ForceJump(oPC, lTarget);
ely_endcombat (1067): ForceJump(oTarget, lLand);
ely_porttoely (44): ForceJump(oParty, lLoc);
farment (28): DelayCommand(3.0, ForceJump(oPC, lTarget));
fky_3endcmb_hell (673): ForceJump(oPC, GetLocation(oBellyWay));
fky_ai_7death (95): ForceJump(oTrapped, lSelf);
fky_arena_7death (62): ForceJump(oPC, lWay);
fky_chat_dmlocal (1037): ForceJump(oDMTarget, Location(oArea, vPos, 0.0));
fky_chat_dmlocal (1065): ForceJump(oDMTarget, GetLocation(oPort));
fky_chat_local (3113): ForceJump(oCPC, lWay);
fky_chat_local (4481): ForceJump(oCPC, GetLocation(GetWaypointByTag("testarea")));
fky_chat_local (4492): ForceJump(oCPC, GetLocation(GetWaypointByTag("home")));
fky_chat_local (6773): ForceJump(oCPC, lTarget);
fky_chat_local (6941): ForceJump(oPet, GetLocation(oCPC));
gen_secret_act (10): ForceJump(oPC, lLoc);
guildcontestport (40): ForceJump(oGuilder, lHome);
guildcontestport (51): DelayCommand(0.5, ForceJump(oGuilder, lHome));
had_enter (246): ForceJump(oPC, lForce);
had_portal_conv (29): ForceJump(oPC, lTarget);
harpersecretcac (14): DelayCommand(1.0, ForceJump(oPC, lArrow));
hellarena_act (145): ForceJump(oPlayer, lWay);
hellenter (104): ForceJump(oPC, GetLocation(GetWaypointByTag("WorkShopHellStart")));
hellenter (251): //ForceJump(oPC, GetLocation(GetWaypointByTag("WorkShopHellStart")));
hellenter (260): ForceJump(oPC, GetLocation(GetWaypointByTag("home")));
hellenter (293): ForceJump (oPC, GetLocalLocation(oPC, "TrapArea_Return"));
hellfinalportal (41): ForceJump(oPC, lTarget);
hell_area_trans (75): ForceJump(oClicker, GetLocation(oTarget));
hell_door_antiex (16): ForceJump(oPC, GetLocation(oWay));
hell_fugue_exit (26): ForceJump(oPC, lTarget);
hell_nessmaze (14): ForceJump(oPC, lLoc2);
hell_port_layer (87): ForceJump(oPC, lTarget);
hell_port_other (39): ForceJump(oPC, lTarget);
hell_port_town (22): ForceJump(oPC, GetLocation(GetWaypointByTag("WanderingWyrmExit")));
hg_antiex_inc (153): ForceJump(oPC, lFugue);
hg_area_enter (335): ForceJump(oPC, lEnter);
hg_area_exit (104): ForceJump(oTrapped, lSelf);
hg_area_inc (46): ForceJump(oPC, lTarget);
hg_area_trans (95): ForceJump(oClicker, GetLocation(oTarget));
hg_client_enter (461): ForceJump(oPC, GetLocation(oWay));
hg_inc (482): void ForceJump (object oTarget, location lTarget, int bClearCombat=TRUE, int bForceCommandable=FALSE);
hg_inc (3879): void ForceJump (object oTarget, location lTarget, int bClearCombat=TRUE, int bForceCommandable=FALSE) {
hg_inc (3884): DelayCommand(5.0, ForceJump(oTarget, lTarget, bClearCombat, bForceCommandable));
hg_inc (3903): DelayCommand(0.1, ForceJump(oTarget, lTarget, bClearCombat, bForceCommandable));
hg_inc (3909): WriteTimestampedLogEntry("FORCEJUMP : " + GetPCPlayerName(oTarget) + " : " +
hg_inc (3914): DelayCommand(1.0, ForceJump(oTarget, lTarget, bClearCombat, ++bForceCommandable));
hg_pillars (172): ForceJump(oTarget, lTarget);
hg_pillars (355): ForceJump(oPC, lTarget);
hg_pillars (362): ForceJump(oPC, lTarget);
hg_respawn (246): ForceJump(oPC, GetLocation(oWay));
hg_updateitems (595): DelayCommand(3.0, ForceJump(OBJECT_SELF, lBurdened));
hiv_trap_trigger (31): ForceJump(oPC, lLoc);
illithiditem003 (63): ForceJump(oPC, GetLocation(oLeader));
jumppedportblast (108): DelayCommand(1.0, ForceJump(oPC, lTarget, FALSE));
legendaltarlimit (11): ForceJump(oPC, GetLocation(GetWaypointByTag("funkywaypoint207")));
loki2_yes (55): ForceJump(oPC, lTarget);
mol_endcombat (257): ForceJump(oSelf, GetLocation(oTarget), TRUE);
mol_pitclimb (17): ForceJump(oPC, lLoc);
mol_pitfall (23): ForceJump(oPC, lLoc);
muscledeath (16): ForceJump (oParty, lLoc);
nw_s0_gate (111): DelayCommand(0.5, ForceJump(si.caster, si.loc));
onenterdocks (19): ForceJump(oPC, lBye);
onenterfugue (12): ForceJump(oPC, lTest);
onentertown (55): ForceJump(oPC, lBurdened);
onentertown (70): ForceJump(oPC, lBye);
pharlanfall (12): ForceJump(oPC, lJump);
phar_port_use (28): ForceJump(oPC, GetLocation(oWay));
ppd_fallbackport (17): ForceJump(oPC, lLoc);
qc_dw_bchant3 (38): ForceJump(oMember, lPC);
qc_dw_bchant3 (57): ForceJump(oMember, lPC);
qc_gi_onhit (91): ForceJump(oTarget, lLoc);
randuse (322): ForceJump(oPC, lJump);
sendtoabyss (66): DelayCommand(3.5, ForceJump(oParty, lAbyss));
teleffectimmorta (4): ForceJump(oPC, lJump);
toy_mechanus (62): DelayCommand(0.2, ForceJump(oTarget, lTarget));
uro_eggclimb (19): ForceJump(oPC, lLoc);
vaultopen1 (48): ForceJump(oPC, GetLocation(oWay));
wkshpwardglw (45): ForceJump(oPC, GetLocation(GetWaypointByTag("home")));
x2_s3_bomb (33): ForceJump(oTarget, si.loc);
Funky
#12
Posté 08 février 2013 - 10:22
I was just trying to understand why you did it that way. You guys are the experts as far as I can tell. So I get curious when I see you doing something different than the way I handle it.
I tend to execute scripts on an object so that garbage collection happens naturally and to take advantage of object_self.
Anyhow, I am sorry for all the questions. I was just trying to get at your thinking and methods.
#13
Posté 08 février 2013 - 10:26
henesua wrote...
Funky,
regarding this:
AssignCommand(oTarget, ClearAllActions(bClearCombat));
AssignCommand(oTarget, ActionJumpToLocation(lTarget));
AssignCommand(oTarget, ActionDoCommand(SetCommandable(TRUE)));
AssignCommand(oTarget, SetCommandable(FALSE));
Does the last assigned command execute first or only before either of the assigned actions?
The First AssignedCommand Clears the ActionQue.
The Second and Third are Executed next only so far as they are placing actions into the Que to be executed later.
The forth Locks the Que so it can not be changed untill the action from the third command unlocks the Que.
#14
Posté 08 février 2013 - 11:03
clear and jump is enough in most cases like transition, portals...henesua wrote...
Fair enough.
I was just trying to understand why you did it that way. You guys are the experts as far as I can tell. So I get curious when I see you doing something different than the way I handle it.
but in order to port a pc doing usuall business it needs to be done with the Funky's method. I know that because I had pvp arena module and we had issues with players remaining in the area after round is finished etc.
#15
Posté 08 février 2013 - 11:10
Doing so would remove the need for all the AssignCommands, and the invalid check at the beginning, and you wouldn't have to pass the target object around as it would be OBJECT_SELF.
Since Funky and crew know what they are doing, I wanted to know why they didn't.
#16
Posté 08 février 2013 - 11:40
#17
Posté 09 février 2013 - 12:07
Market Pricing Musings
The code that's resulted so far is as follows. The comments at the bottom are mostly correct, but outdated - I decided to see the fake history with average rate of sale meeting desired rate of sale, so prices will drop slowly to start. The core concept is to peg prices with a minimum of disruption to the market, by increasing supply by a fixed amount, by pegging price change and price change speed to rates of purchase. The commented out CREATE TABLES at top are far from final as well - I can't index them until I've seen all the calls, and they'll likely have additional columns, like playername in the history table.
void LoadAugShop();
void LoadAugDisplay();
void AdjustPricesAfterSale();
/*
mshop_aug_inv
mi_aug, mi_price, mi_avail, mi_sold
mshop_aug_his
mh_id (autoinc), mh_aug, mh_date, mh_price (price only in case we want to use in the future)
tracks current price, avail, sold, aug#
join aug tables for rarity on aug #
CREATE TABLE mshop_aug_his (mh_id INT(11) default NULL auto_increment primary key, mh_aug INT UNSIGNED default NULL, mh_price BIGINT(20) default NULL, mh_date DATETIME default NULL);
CREATE TABLE mshop_aug_inv (mi_aug INT UNSIGNED NOT NULL primary key, mi_price BIGINT(20) default NULL, mi_avail TINYINT UNSIGNED default NULL, mi_sold TINYINT UNSIGNED default NULL);
*/
void LoadAugShop() {
if (GetLocalString(GetModule(), "ServerNumber") != "111")
return;
object oOwnerWay = GetWaypointByTag("wp_aug_shop_own");
object oCaseWay = GetWaypointByTag("wp_aug_shop_case");
object oCase = CreateObject(OBJECT_TYPE_PLACEABLE, "aug_shop_display", GetLocation(oCaseWay));
/*
calc ARoS/DRoS by rarity (Actual and Desired Rate of Sale) - DRoS is pegged, ARoS is measured using
history, with fake sales meeting ARoS calculated in for first 90 day period
*/
float fARoSUR, fDRoSUR = 0.1666;//1 per 6 resets
float fARoSR, fDRoSR = 0.25; //1 per 4
float fARoSUC, fDRoSUC = 0.5; //1 per 2
float fARoSC, fDRoSC = 1.0; //1 per 1
//purge old records? Not for now, sales data potentially useful
//Get Actual Rate of Sale for the 4 rarities in last 90 days
string sSQL = "SELECT FLOOR(ra_rarity/1000000) AS a, COUNT(*) FROM rip_augments, mshop_aug_his " +
"WHERE ra_id = mh_aug AND DATEDIFF(NOW(), mh_date) < 90 AND FLOOR(ra_rarity/1000000) < 5 " +
"GROUP BY a ORDER BY a ASC";
int nRarity, nSales, nSaleCountUR, nSaleCountR, nSalecountUC, nSaleCountC;
object oModule = GetModule();
SQLExecDirect(sSQL);
while (SQLFetch() != SQL_ERROR) {
nRarity = StringToInt(SQLGetData(1));
nSales = StringToInt(SQLGetData(2));
switch (nRarity) {
case 1: nSaleCountC = nSales; break;
case 2: nSalecountUC = nSales; break;
case 3: nSaleCountR = nSales; break;
case 4: nSaleCountUR = nSales; break;
default: break;
}
}
//seed virtual fake sells for first 90 days via math - keeps real history clean and
//gives low RoD/RoI to start (prices will begin high)
sSQL = "SELECT DATEDIFF(NOW(), '2013-02-08 23:59:59')";
int nDays;
SQLExecDirect(sSQL);
if (SQLFetch() != SQL_ERROR) {
nDays = StringToInt(SQLGetData(1));
}
//calc current Actual Rates of Sale for rarities adjusted for fake sales
//90 days is roughly 180 resets, give or take, fDRoS's are per reset
fARoSC = (nSaleCountC/180.0) + (nDays < 90 ? ((90-nDays)*2.0*fDRoSC) : 0.0);
fARoSUC = (nSalecountUC/180.0) + (nDays < 90 ? ((90-nDays)*2.0*fDRoSUC) : 0.0);
fARoSR = (nSaleCountR/180.0) + (nDays < 90 ? ((90-nDays)*2.0*fDRoSR) : 0.0);
fARoSUR = (nSaleCountUR/180.0) + (nDays < 90 ? ((90-nDays)*2.0*fDRoSUR) : 0.0);
//calc price drops from last sales period RoD = .19*x^2 – 0.38*x +.02; x = AROS/DROS
float fSalesRatioC = fARoSC/fDRoSC;
float fSalesRatioUC = fARoSUC/fDRoSUC;
float fSalesRatioR = fARoSR/fDRoSR;
float fSalesRatioUR = fARoSUR/fDRoSUR;
float fRoDC = (0.19 * pow(fSalesRatioC, 2.0)) - (0.38 * fSalesRatioC) + 0.02;
float fRoDUC = (0.19 * pow(fSalesRatioUC, 2.0)) - (0.38 * fSalesRatioUC) + 0.02;
float fRoDR = (0.19 * pow(fSalesRatioR, 2.0)) - (0.38 * fSalesRatioR) + 0.02;
float fRoDUR = (0.19 * pow(fSalesRatioUR, 2.0)) - (0.38 * fSalesRatioUR) + 0.02;
//select rarity, aug from table where mi_avail - set
mshop_aug_inv
mi_aug, mi_price, mi_avail, mi_sold
//for each, decrement price for that aug by RoD*.7
//for each, decrement price of each of that type by RoD*.25
//for each, decrement price of each of that rarity by*.05
}
/*
Price is adjusted on each sale, increasing by the current RoI for that rarity, based on the current rate of sale
for that rarity. This adjustment on point of sale allows us to make multiples of the augs in the shop each reset
available, because it increases price to prevent runs. Moreover, it increasingly increases price if they buy another.
The net effect of this is to increase liquidity, and thereby the accuracy of market information for players. The
only catch is that we'll have to seed a fake history (which is easy) to simulate current rate of sale > desired rate
of sale to start, so that the starting elasticity will be high, and will not decrease after the first sale (as it
would if the history showed zero sales in the last 90 days - 1/90 is closer to desired rate of sale than 0/90).
Price is also adjusted on shop load, after server load. We check the database to see which items were available last
reset, and which of those were sold.
For available items:
If sold, we increase price on all items of that rarity by a percentage of the current RoI for that rarity. That
percentage is based on the number of items of that rarity, let's call that NIoR. If we have 150 items of that rarity,
we would adjust the prices of all items of that rarity up by (1/150*RoI), or RoI/NIoR.
If not sold, we decrease price on all items of that rarity by a percentage of the current RoD: RoD/NIoR.
further:
If sold, we increase price on all items of that type (a smaller subset than rarity) by a percentage based on the
number of items of that type (NIoT), or RoI/NIoT.
If not sold, we decrease price on all items of that type by RoD/NIoT.
We peg changing elasticities to DRoS by rarity rather than type because assigning a desired rate of sale to types would cause more distortions in pricing.
*/
Funky





Retour en haut






