This is a read only copy without any forum functionality of the old Modcraft forum.
If there is anything that you would like to have removed, message me on Discord via Kaev#5208.
Big thanks to Alastor for making this copy!

Menu

Author Topic: [C++]  StockExchange NPC Script  (Read 2878 times)

Roarl

  • Registred Member
  • LUA Script Tinker
  • *****
  • Posts: 46
    • View Profile
[C++]  StockExchange NPC Script
« on: July 24, 2015, 10:14:24 pm »
Hi guys,
I've been trying to write a StockExchange NPC Script for some 20 hours now, but I can't get it working (no wonder tho, I'm still very new to C++ ... DON'T HIT ME PLEASE :3 )

This script would use data from two different tables
 1) 'stocks' in WorldDatabase
     It contains four different fields : iD (Primary key) as an int, Name (name of the stock) as text, Scale (I'd use that once to balance the stocks easily without havint to recompile) as an int, and OwnedRatio (represents which ratio of the stock is owned by players (-> available ratio is thus (1-OwnedRatio)
     There would be a row for every existing stock.
2) 'character_stockdata' in CharacterDatabase
     Contains iD (player GUID, Primary key), 1, 2, 3, 4 and 5 (these are fields for the five different stocks I want to use, could add some later if I ever feel like it). 1, 2, 3, 4, 5 are floats because they are ratios just like ownedratio.

So basically, I came here because it keeps crashing when I sell the stocks ingame.
(That would be, in the SellStock function (first function of the class if I remember correctly).
Buying stocks works just fine, the ratio bought by the player (saved in 1, 2, 3, 4, 5 according to the stock) is correctly added to OwnedRatio...

Could you guys have a look at it? I'll keep trying to solve that problem in the meantime of course, I'm no lazy shit (well at least not for wow modding heheh ).
Ow, also wanted to say that I entirely acknowledge this code's lack of comments and it's poor writing style... As I said I'm a beginner (very first C++ script), so I'm open to any suggestion.

I will translate this into English and release it here once it's properly working, in case it would interest someone. :)

Thanks for your time and consideration! :)

UP :  My CPU fan is out of service, soooo... The English translation and script cleanup might wait a trifle longer, time for me to get a replacement!

Here's the code :
 
Code: [Select]
/*
0.0.3
StockExchange NPC Script

Description
-----------
The script uses 5 different functions (as functions of time) to "represent" the exchange rates of 5 different stocks.
Players can buy and sell shares of those stocks, provided they have bought a licence first.


TODO
-----------
#1 DEMAND SHOULD AFFECT RATES => IMPROVE & CLEAN STOCKFUNCTION

Credits to Rochet2 for the nice menu look and for cleaning this script up a trifle ( OKAY, maybe it was a lot :3).
*/

#include "ScriptPCH.h"
#include "Config.h"
#include "ScriptedCreature.h"
#include "Language.h"
#include "time.h"
#include <cmath>

#define STOCKNUMBER 5

namespace
{
class CS_StockExchange : public CreatureScript
{
public:
CS_StockExchange() : CreatureScript("Creature_StockExchange") { }



bool OnGossipHello(Player* plr, Creature* creature) override //MAIN MENU
{
WorldSession* session = plr->GetSession();
QueryResult licencetest = CharacterDatabase.PQuery("SELECT `1`, `2`, `3`, `4`, `5`  FROM `character_stockdata` WHERE iD = %u", plr->GetGUIDLow());
plr->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, "|TInterface/ICONS/INV_Scroll_08:30:30:-18:0|tQuels sont les cours actuels du marche?", GOSSIP_SENDER_MAIN, 2);
plr->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, "|TInterface/ICONS/INV_Misc_Book_11:30:30:-18:0|tQuelles actions sont en ventes?", GOSSIP_SENDER_MAIN, 1);
if (!licencetest)
{
plr->ADD_GOSSIP_ITEM_EXTENDED(GOSSIP_ICON_MONEY_BAG, "|TInterface/ICONS/INV_MISC_NOTE_02:30:30:-18:0|tJe veux acheter une licence d'investissement.", GOSSIP_SENDER_MAIN, 12, "Cette action vous coutera", 400000, false);
}
else //Player can invest if he has a licence
{
plr->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, "|TInterface/ICONS/INV_Misc_Coin_02:30:30:-18:0|tJ'aimerais gerer mes investissements.", GOSSIP_SENDER_MAIN, 3);
}
plr->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, "|TInterface/ICONS/Ability_Spy:30:30:-18:0|tUn plaisir d'avoir fait affaire avec vous.", GOSSIP_SENDER_MAIN, 4);
plr->SEND_GOSSIP_MENU(DEFAULT_GOSSIP_MESSAGE, creature->GetGUID());
return true;
}

bool OnGossipSelect(Player* plr, Creature* creature, uint32 sender, uint32 uiAction) override
{
uint32 stock = 0;
int32 amount = 0;
plr->PlayerTalkClass->ClearMenus();
WorldSession* session = plr->GetSession();
std::ostringstream message;
float ownedratio[5];
int scale[5];
for (int iter = 1; iter < 6; iter++)
{
QueryResult result = WorldDatabase.PQuery("SELECT `OwnedRatio`,`Scale`  FROM `stocks` WHERE iD = %u", iter);
if (!result)
return false;
Field* field = result->Fetch();
ownedratio[iter-1]= field[0].GetFloat();
scale[iter-1] = field[1].GetInt32();
}
switch (uiAction)
{
case 1: //REMAINING STOCKS
message << "ACTIONS A VENDRE SUR MARCHE$BManoir de Ravenholdt : " << StockFunction(1)*scale[0] * (1 - ownedratio[0]) << "$BLa Voile Sanglante : " << StockFunction(2)*scale[1] * (1 - ownedratio[1]) << "$BCartel Fusetincelle : " << StockFunction(3)*scale[2] * (1 - ownedratio[2]) << "$BMarchands de soie de Theramore : " << StockFunction(4)*scale[3] * (1 - ownedratio[3]) << "$BEldoar'norore : " << StockFunction(5)*scale[4] * (1 - ownedratio[4]);
creature->Whisper(message.str(), LANG_UNIVERSAL, plr);
plr->PlayerTalkClass->SendCloseGossip();
OnGossipHello(plr, creature);
break;
case 2: //CURRENT EXCHANGE RATES
message << "COURS ACTUELS DU MARCHE$BManoir de Ravenholdt : " << StockFunction(1)*scale[0] << "$BLa Voile Sanglante : " << StockFunction(2)*scale[1] << "$BCartel Fusetincelle : " << StockFunction(3)*scale[2] << "$BMarchands de soie de Theramore : " << StockFunction(4)*scale[3] << "$BEldoar'norore : " << StockFunction(5)*scale[4];
creature->Whisper(message.str(),LANG_UNIVERSAL, plr);
plr->PlayerTalkClass->SendCloseGossip();
OnGossipHello(plr, creature);
break;
case 3: //MANAGE PORTFOLIO MENU (5-10)
plr->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, "|TInterface/ICONS/INV_Helmet_30:30:30:-18:0|tManoir de Ravenholdt", GOSSIP_SENDER_MAIN, 5);
plr->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, "|TInterface/ICONS/INV_Helmet_66:30:30:-18:0|tLa Voile Sanglante", GOSSIP_SENDER_MAIN, 6);
plr->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, "|TInterface/ICONS/INV_Misc_Bomb_03:30:30:-18:0|tCartel Fusetincelle", GOSSIP_SENDER_MAIN, 7);
plr->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, "|TInterface/ICONS/INV_Chest_Cloth_56:30:30:-18:0|tMarchands de soie de Theramore", GOSSIP_SENDER_MAIN, 8);
plr->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, "|TInterface/ICONS/INV_Misc_FireDancer_01:30:30:-18:0|tEldoar'norore", GOSSIP_SENDER_MAIN, 9);
plr->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, "|TInterface/ICONS/Ability_Spy:30:30:-18:0|tRetour au menu principal", GOSSIP_SENDER_MAIN, 10);
plr->SEND_GOSSIP_MENU(50002, creature->GetGUID());
break;
case 4: //CLOSE GOSSIP
plr->PlayerTalkClass->SendCloseGossip();
break;
case 5: //MANAGE RAVENHOLDT STOCK
stock = 1;
plr->ADD_GOSSIP_ITEM_EXTENDED(GOSSIP_ICON_MONEY_BAG, "|TInterface/ICONS/INV_Letter_03:30:30:-18:0|tAcheter des parts", stock, 0, "Combien de pieces d'or desirez-vous investir?", 0, true);
plr->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, "|TInterface/ICONS/INV_Misc_Coin_16:30:30:-18:0|tVendre les parts", stock, 11);
plr->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, "|TInterface/ICONS/Ability_Spy:30:30:-18:0|tRetour au menu precedent", GOSSIP_SENDER_MAIN, 3);
plr->SEND_GOSSIP_MENU(50002, creature->GetGUID());
return true;
break;
case 6: //MANAGE BLOODSAIL STOCK
stock = 2;
plr->ADD_GOSSIP_ITEM_EXTENDED(GOSSIP_ICON_MONEY_BAG, "|TInterface/ICONS/INV_Letter_03:30:30:-18:0|tAcheter des parts", stock, 0, "Combien de pieces d'or desirez-vous investir?", 0, true);
plr->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, "|TInterface/ICONS/INV_Misc_Coin_16:30:30:-18:0|tVendre les parts", stock, 11);
plr->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, "|TInterface/ICONS/Ability_Spy:30:30:-18:0|tRetour au menu precedent", GOSSIP_SENDER_MAIN, 3);
plr->SEND_GOSSIP_MENU(50002, creature->GetGUID());
break;
case 7: //MANAGE GOBLIN STOCK
stock = 3;
plr->ADD_GOSSIP_ITEM_EXTENDED(GOSSIP_ICON_MONEY_BAG, "|TInterface/ICONS/INV_Letter_03:30:30:-18:0|tAcheter des parts", stock, 0, "Combien de pieces d'or desirez-vous investir?", 0, true);
plr->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, "|TInterface/ICONS/INV_Misc_Coin_16:30:30:-18:0|tVendre les parts", stock, 11);
plr->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, "|TInterface/ICONS/Ability_Spy:30:30:-18:0|tRetour au menu precedent", GOSSIP_SENDER_MAIN, 3);
plr->SEND_GOSSIP_MENU(50002, creature->GetGUID());
break;
case 8: //MANAGE SILKTRADERS STOCK
stock = 4;
plr->ADD_GOSSIP_ITEM_EXTENDED(GOSSIP_ICON_MONEY_BAG, "|TInterface/ICONS/INV_Letter_03:30:30:-18:0|tAcheter des parts", stock, 0, "Combien de pieces d'or desirez-vous investir?", 0, true);
plr->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, "|TInterface/ICONS/INV_Misc_Coin_16:30:30:-18:0|tVendre les parts", stock, 11);
plr->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, "|TInterface/ICONS/Ability_Spy:30:30:-18:0|tRetour au menu precedent", GOSSIP_SENDER_MAIN, 3);
plr->SEND_GOSSIP_MENU(50002, creature->GetGUID());
break;
case 9: //MANAGE ELDOAR'NORORE STOCK
stock = 5;
plr->ADD_GOSSIP_ITEM_EXTENDED(GOSSIP_ICON_MONEY_BAG, "|TInterface/ICONS/INV_Letter_03:30:30:-18:0|tAcheter des parts", stock, 0, "Combien de pieces d'or desirez-vous investir?", 0, true);
plr->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, "|TInterface/ICONS/INV_Misc_Coin_16:30:30:-18:0|tVendre les parts", stock, 11);
plr->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, "|TInterface/ICONS/Ability_Spy:30:30:-18:0|tRetour au menu precedent", GOSSIP_SENDER_MAIN, 3);
plr->SEND_GOSSIP_MENU(50002, creature->GetGUID());
return true;
break;
case 11: //TRANSACTION = SELL
if (!SellStock(plr, stock))
plr->GetSession()->SendNotification("Erreur lors de la vente des parts");
plr->PlayerTalkClass->SendCloseGossip();
OnGossipHello(plr, creature);
break;
case 12: //CREATE PLAYER LICENCE ( = ROW IN CHARACTER_STOCKDATA )
if (plr->GetMoney() >= 400000)
{
if (CreateLicence(plr))
{
amount = 400000;
plr->ModifyMoney(-amount);
message << "Votre licence a ete achetee avec succes, " << plr->GetName() << "!";
   creature->Say(message.str(), LANG_UNIVERSAL, plr);
}
else
plr->GetSession()->SendNotification("Erreur lors de l'enregistrement de votre licence... Prenez contact avec l'administrateur.");
}
else
{
message << "Navre, " << plr->GetName() << ", vous n'avez pas ces quarantes pieces d'or...";
creature->Say(message.str().c_str(), LANG_UNIVERSAL, plr);
}

plr->PlayerTalkClass->SendCloseGossip();
OnGossipHello(plr, creature);
break;
default:
OnGossipHello(plr, creature);
break;
}

return true;
}
bool OnGossipSelectCode(Player* plr, Creature* creature, uint32 stock, uint32 uiAction, const char* code) override
{
plr->PlayerTalkClass->ClearMenus();
std::ostringstream message;
int32 amount = 0;

std::string investment = code;
static const char* allowedcharacters = "1234567890";
if (!investment.length() || investment.find_first_not_of(allowedcharacters) != std::string::npos) //If investment was specified incorrectly
{
plr->GetSession()->SendNotification("L'investissement doit-être declare en chiffres. N'utilisez que 0,1,2,3,4,5,6,7,8 et 9, stupide ignare que vous etes.");
}
else //If investment was specified properly
{
//Statements
uint32 investmentI = uint32(atol(code) * 10000);
if (investmentI <= plr->GetMoney())
{
double stockfunction = StockFunction(stock);

QueryResult result1 = WorldDatabase.PQuery("SELECT `OwnedRatio`,`Scale`  FROM `stocks` WHERE iD = %u", stock);
if (!result1)
return false;
Field* field = result1->Fetch();
float ownedratio = field[0].GetFloat();
int scale = field[1].GetInt32();
QueryResult result2 = CharacterDatabase.PQuery("SELECT `%u` FROM `character_stockdata` WHERE iD = %u", stock, plr->GetGUIDLow());
if (!result2)
return false;
field = result2->Fetch();
float initialratio = field[0].GetFloat();
float ratio = investmentI / scale / stockfunction;
if (ratio <= (1-ownedratio)) //If enough stocks left
{
int amount = investmentI;
plr->ModifyMoney(-amount);  // substract it from player money
CharacterDatabase.PExecute("UPDATE `character_stockdata` SET `%u` = %f WHERE `iD` = %u", stock, initialratio + ratio, plr->GetGUIDLow());
WorldDatabase.PExecute("UPDATE `stocks` SET `OwnedRatio` = %f WHERE `iD` = %u", ownedratio + ratio, stock);
}
else
{
plr->GetSession()->SendNotification("Il n'y a pas assez de parts a acheter pour le montant que vous voulez investir, consultez les parts restantes avant d'investir.");
}

}
else
{
message << "Vous n'avez pas tout cet argent a investir, " << plr->GetName() << ".";
creature->Say(message.str().c_str(), LANG_UNIVERSAL, plr);
}
}

plr->PlayerTalkClass->SendCloseGossip();
OnGossipHello(plr, creature);
return true;
}

private :
bool SellStock(Player* plr, uint32 stock) /*SELL ALL THE SHARES OF THE SPECIFIED STOCK */
{
QueryResult result2 = WorldDatabase.PQuery("SELECT `OwnedRatio`,`Scale`  FROM `stocks` WHERE iD = %u", stock);
if (!result2)
return false;
QueryResult result1 = CharacterDatabase.PQuery("SELECT `1`, `2`, `3`, `4`, `5`  FROM `character_stockdata` WHERE iD = %u", plr->GetGUIDLow());
if (!result1)
return false;
Field* field = result1->Fetch();
float ratio = field[stock - 1].GetFloat();
if (ratio == 0)
{
plr->GetSession()->SendNotification("Vous n'avez aucune part a vendre pour ce marche...");
}
else //ONLY IF PLAYER OWNS SOMETHING
{
Field* field = result2->Fetch();
float ownedratio = field[0].GetFloat();
int scale = field[1].GetInt32();
double stockfunction = StockFunction(stock);


plr->ModifyMoney(int32(scale*stockfunction*ratio));  // add it to player money
CharacterDatabase.PExecute("UPDATE `character_stockdata` SET `%u` = 0 WHERE `iD` = %u", stock, plr->GetGUIDLow());
WorldDatabase.PExecute("UPDATE `stocks` SET `OwnedRatio` = %f WHERE `iD` = %u", ownedratio - ratio, 1);
}
return true;
}

bool CreateLicence(Player* plr)
{
SQLTransaction trans = CharacterDatabase.BeginTransaction();
trans->PAppend("REPLACE INTO `character_stockdata` (`iD`, `1`, `2`, `3`, `4`, `5`) VALUES (%u, 0, 0, 0, 0, 0)", plr->GetGUIDLow());
CharacterDatabase.CommitTransaction(trans);
return true;
}

double StockFunction(uint32 stock) /* Works out the current exchange rate according to time ellapsed since stock market release */
{
// HOW MUCH TIME HAS PASSED...
time_t now;
struct tm y2k;
double minutes;

time(&now); //...UNTIL NOW...
y2k = *localtime(&now);
y2k.tm_hour = 18;   y2k.tm_min = 20; y2k.tm_sec = 0;
y2k.tm_year = 115; y2k.tm_mon = 6; y2k.tm_mday = 27; //...SINCE STOCK MARKET RELEASE (This date might be updated at some point)

minutes = abs(difftime(mktime(&y2k), now)) / 3600;

switch (stock)
{
case 1: //Ravenholdt
return (10 + 3 * sin(0.3* minutes) + sin(3 * minutes));
break;
case 2: //Bloodsail
return (-atan(tan(minutes)) + 2);
break;
case 3: //Goblin
return (2 + sin(30 * minutes)*cos(100 * minutes));
break;
case 4: //SilkTraders
return (atan(tan(minutes)) + 2 + 0.1*minutes);
break;
case 5: //Eldoar'norore
return (0.3*minutes + sin(5 * minutes)*cos(10 * minutes) + 1);
break;
default:
return 0;
break;
}
}
};
}

void AddSC_Stock()
{
new CS_StockExchange();
}

« Last Edit: August 04, 2015, 02:54:58 pm by Admin »

Rochet2

  • Contributors
  • Polygonshifter
  • *****
  • Posts: 59
    • View Profile
    • http://rochet2.github.io/
Re: [C++]  StockExchange NPC Script
« Reply #1 on: July 25, 2015, 01:35:00 am »
Going to sleep myself now, but you could try:

If you are on windows, set the compile mode to debug and try crashing again. There should be a crash log in the server folder / crashes. http://prntscr.com/7wnmvp
You can also try debugging easily after compiling in debug by using attach to process.
Open the TrinityCore.sln (or whatever core you use) and start the server normally. Then in visual studio click this: http://prntscr.com/7wnngg
Then choose worldserver and you are debugging the code.
From there you can either crash the script and the debugger will move to that point or you can set break points by clicking the "gutter" http://prntscr.com/7wnnp5
The text file is what you want to look at in the crash logs. The dmp file can be dragged to visual studio and it will show as if you were debugging at that time (shows call stacks, local variables and everything)

On linux you would need to use gdb to debug and TC provides a GDB file for creating crash logs I assume
See and read more at: https://github.com/TrinityCore/TrinityC ... b/debugger

You can here as well try use the gdb with the debugger file like the TC link readme tells you and let the core crash without actually using the debugger with break points etc and it should proabably output a log automatically similar to windows.


I hope you can get to some crash logging and debugging to make future ventures easier :)
I myself discovered these tools WAY too late.


Crash logs may not be that useful always, but most of the time (at least on windows) they provide a huge amount of useful information .. like .. what line crashed.
Here is a log example from my own crashes on windows from when I was developing today:
http://pastebin.com/0K0CBYa5
it has all kind of information like branch and commit, but the most important is the call stack which shows at top where the program crashed and what was called to get to that crashing point.
Below the call stack is a bunch of local variables and similar info.
on linux you would expect to see something similar.
« Last Edit: January 01, 1970, 01:00:00 am by Admin »

Roarl

  • Registred Member
  • LUA Script Tinker
  • *****
  • Posts: 46
    • View Profile
Re: [C++]  StockExchange NPC Script
« Reply #2 on: July 25, 2015, 11:11:39 am »
Thanks for the ->immediate<- reply.

I'm on Wndows indeed (forgot to mention it earlier, my apologies), I'll compile in debug mode as you said straightaway.!

And thank you for your suggestion! I'll do some research about crash logging so I can implement it in my next scripts. I guess you are right,  it must be an enormous time saving.

What are you working on atm? :)
« Last Edit: January 01, 1970, 01:00:00 am by Admin »

Rochet2

  • Contributors
  • Polygonshifter
  • *****
  • Posts: 59
    • View Profile
    • http://rochet2.github.io/
Re: [C++]  StockExchange NPC Script
« Reply #3 on: July 25, 2015, 12:43:55 pm »
Working on coding Eluna multithreaded version.
Should work on a PR as well .. and hoover since its saturday.

You dont actually need to do anything to your script to have the crash logs etc I just said. :3

Some notes:
Do not store variables like _stock unless you REALLY have to. They are subject to race conditions in some cases and they are shared between users using the gossip on any NPCs using the same script.
So even if you have 2 players on same NPC using the script, they may mess up eachother's choices in the script. Its better to use the sender and action to pass data around gossip and if something needs to be stored outside, store it to the player class or similar. (depends on situation)
I think its a waste sometimes when something like GOSSIP_SENDER_MAIN is used as sender.

Spell, aura, creature and gameobject AI scripts are different and in those you can store member variables to the script class. But do not store anything to the base script classes you use like CreatureScript and PlayerScript and so.

Use the override keyword if possible. It will make sure the script operates correctly in the future and makes your own typos and other mistakes show.

Since gossip is handled in thread safe environment, it delays ALL actions on the server for the time the script runs. For that reson it would be important to keep it efficient. And one thing that is not efficient at all is database querying in real time. PExecute (and Execute) should be asynchronous (delayed/queued) though, so that /should/ be alright.
Load the needed data on start up or player log in or similar so its loaded beforehand and doesnt need loading all the time when using the script
That way you wont probably need to resort to hacks like this; SELECT %u FROM.
Database actions should be file reads, so having an SSD would speed the database. File IO is way slower than RAM access.

Post the database SQL code and data with the script. Its not always easy to just read a random script and see whats wrong and testing it is not a walk in the park without the database structure and code. Also the database structure could be faulty - many use bad database table structures without being aware how it may affect their script.
For example what data do you have in stock table?

Note that those talk and similar functions can be spammed. You can hit some action and everyone gets their chat and screen spammed with text.
Note that investment can be 99999. was this intended?

When testing, I dont have any crash.

Note that UPDATE `character_stockdata` SET `1` = %u WHERE `iD` = %f
here you mixed %u and %f.
Note that in SellStock you use result1 before checking if it is null. Check EVERY query! (if (!result) return)


PS. I hope you are using some sane IDE like Visual Studio to code your scripts.
« Last Edit: January 01, 1970, 01:00:00 am by Admin »

Roarl

  • Registred Member
  • LUA Script Tinker
  • *****
  • Posts: 46
    • View Profile
Re: [C++]  StockExchange NPC Script
« Reply #4 on: July 25, 2015, 02:51:33 pm »
Changelog :
[paragraph:2knebdee]
  • Removed "_stock" protected variable from CreatureScript class, instead used stock as sender when required
  • Removed those rather ugly switches on "stock" in the SellStock and OnGossipSelectCode functions, instead used %u to specify the targetted field
  • Used (tried to at least) the new "override" keyword because c++11 is awesome (not sure I used it correctly :O)
  • Changed the say into a whisper so the player can only spam their own chat
  • Changed functions SellStock, StockFunction and CreateLicence from public to private, we don't need them elsewhere atm right? Also put them at the end of the code for readability purposes.
[/paragraph:2knebdee]

Nice, it's an exciting and lovely project. :)
Does PR stand for project revision? (Yeah I'm blissfully ignorant). Haha good luck with the hoovering. x)

Thank you once more for your remarks and for your patience!  Took them into account (code is updated).
Here are the sql files :
characters.sql
world.sql

Quote
Since gossip is handled in thread safe environment, it delays ALL actions on the server for the time the script runs. For that reson it would be important to keep it efficient. And one thing that is not efficient at all is database querying in real time. PExecute (and Execute) should be asynchronous (delayed/queued) though, so that /should/ be alright.
Load the needed data on start up or player log in or similar so its loaded beforehand and doesnt need loading all the time when using the script. That way you wont probably need to resort to hacks like this; SELECT %u FROM.
Database actions should be file reads, so having an SSD would speed the database. File IO is way slower than RAM access.

Seems to be more reasonable indeed... However if I did load the needed data only on player log in, the  remaining stocks wouldn't be updated correctly in-game as long as the player didn't reload, would them? As the OwnedRatios change every time a player buys a stock share... Or did I get you wrong? :O

And that say thing is  truly very messy... I'll make it a whisper! :)

Quote
Note that investment can be 99999. was this intended?

Erm, whut? Yeah I think investment could be 99999. But why do you object? Is something wrong with that? (Just asking huh don't take my question as pride or something, just trying to understand what the issue is :3 )

Regards! =)
« Last Edit: January 01, 1970, 01:00:00 am by Admin »

Rochet2

  • Contributors
  • Polygonshifter
  • *****
  • Posts: 59
    • View Profile
    • http://rochet2.github.io/
Re: [C++]  StockExchange NPC Script
« Reply #5 on: July 25, 2015, 05:32:26 pm »
PR would be a github pull request.

Did you fix the crash? Did you get the debugging and or crash logging working?

I was just noting about the investment. I ignored what the purpose of the code was and simply analyzed the code. Seemed the code said only use 1.2.3.4. etc and nothing about using higher values.

If you keep the stock data in RAM and when you update it, update it to both to RAM and to DB.
That way the info in both places is uptodate and you can get the correct data in code at any time with simply using the stored data. Like I mentioned earlier, using Exeute to update the database should be less heavy than using Query.
Though its a bit hard for me to see how this ratio thing works .. I feel like storing a float ratio is a bad thing since rounding could make it screw up so that its over or under allowed. Not that I checked if that is possible in the code.

You seem to be using Query/PQuery for all your database actions. What is wrong with using Execute?
You should change all SQL statements where you do not actually fetch any data into Execute, PExecute or DirectExecute or PDirectExecute.
« Last Edit: January 01, 1970, 01:00:00 am by Admin »

Roarl

  • Registred Member
  • LUA Script Tinker
  • *****
  • Posts: 46
    • View Profile
Re: [C++]  StockExchange NPC Script
« Reply #6 on: July 25, 2015, 10:16:54 pm »
I see. :)

I compiled in debug mode but I couldn't make the crash happen again... I have no idea why it crashed in the first place but if it ever happens again at least I know how to debug it thanks to you.

Yeah, I don't think it needs a limit but once more I might be wrong.

I updated the code and changed every instance of PQuery used only to fetch data from DB into an Execute as recommended!

I'll start working on an English translation next week, time for me to test it and improve it a little bit more.

As far as ratios are concerned, I have to say it's the best way I figured to take into account exchange rates variations. That doesn't mean there ain't another way for it, but rather that's the one I preferred. Do you think I ought to use double instead of float? Or straight out change this ratio system?

Thank you. :)
« Last Edit: January 01, 1970, 01:00:00 am by Admin »