+++ DYNRPG - THE RM2K3 PLUGIN SDK +++

Posts

Hey guys. Last night I finished a sweet little plugin that will calculate game playtime. At first, I was trying to do this with the date/time plugin, but realized it would be easier to write a new plugin for it, so here it is! I haven't added configuration stuff yet, so for now, just change the variables to the ones you want to assign to.

Here's how it works: Using GetTickCount, it calculates the number of seconds between a starting time (beforeTimeSecs) and the current time (afterTimeSecs). This is considered the "session time." beforeTimeSecs can either be initialized at the time of a new game, when a game is loaded, or it can be forced by setting a variable (4010) to a certain point in time (in seconds). It then adds that to the previous combined session time (if applicable) and then calculates the hours, minutes, and seconds on the fly. You'll find (hopefully) that it's 100% accurate, and it won't matter what's onscreen in your RPG at any given time. The clock will always be active in the background.

When you save your game, your session will be logged in variable 4006 (PlaytimeSecs), and then when you load your game again (starting a new session), it will be added to your previous one.

This was built and tested on a 3 year old netbook with an intel atom processor, and it runs without lag, so you shouldn't have any issues with that.

Without further adieu:

Playtime Clock

Variables
4003:Time-SessionStart - Storse the cpu time the session started (in seconds)
4004:Time-SessionCurrent - Stores the cpu time the session is currently on (in secs)
4005:Time-SessionSecs - Stores the difference (in secs)
4006:Time-PlaytimeSecs - This is your total gameplay time on a particular save. This can only be edited to a specific value by setting the RestartTrigger.
4007:Time-PlaytimeHH - Hour digit (Max is 65535)
4008:Time-PlaytimeMM - Minute digit
4009:Time-PlaytimeSS - Second digit
4010:Time-RestartTrigger - Used to manually set the playtime to a certain time


#define AUTO_DLLMAIN
#include <DynRPG/DynRPG.h>

unsigned long int beforeTimeTicks;
unsigned long int beforeTimeSecs;
unsigned long int afterTimeTicks;
unsigned long int afterTimeSecs;
unsigned long int sessionSecs;
unsigned long int playtimeSecs;
unsigned long int playtimeSecsMath;
unsigned short int playtimeHH;
unsigned char playtimeMM;
unsigned char playtimeSS;

void onLoadGame (int id, char* data, int length) { // Starts a new play session
beforeTimeTicks = GetTickCount();
beforeTimeSecs = beforeTimeTicks/1000;
RPG::variables[4003] = beforeTimeSecs;
playtimeSecs = RPG::variables[4006];
}

void onNewGame () {
beforeTimeTicks = GetTickCount();
beforeTimeSecs = beforeTimeTicks/1000;
RPG::variables[4003] = beforeTimeSecs;
playtimeSecs = 0;
}

bool onSetVariable (int id, int value) {
if (id == 4010){
beforeTimeTicks = GetTickCount();
beforeTimeSecs = beforeTimeTicks/1000;
RPG::variables[4003] = beforeTimeSecs;
playtimeSecs = value;
}
return true;
}

void onFrame (RPG::Scene scene) {
afterTimeTicks = GetTickCount();
afterTimeSecs = afterTimeTicks/1000;
RPG::variables[4004] = afterTimeSecs;
sessionSecs = afterTimeSecs - RPG::variables[4003];
RPG::variables[4005] = sessionSecs; // Session seconds

playtimeSecsMath = playtimeSecs + sessionSecs;
RPG::variables[4006] = playtimeSecsMath; // Total playtime seconds

playtimeHH = playtimeSecsMath/3600; // Calculate hours
RPG::variables[4007] = playtimeHH; // Store hours

playtimeSecsMath = playtimeSecsMath%3600; // Get the remainder from hours
playtimeMM = playtimeSecsMath/60; // Calculate minutes
RPG::variables[4008] = playtimeMM; // Store minutes

playtimeSS = playtimeSecsMath%60; // Get the remainder from minutes & calculate seconds
RPG::variables[4009] = playtimeSS; // Store seconds
}

Easily display via DynText:

Initialization event:

Comment: @write_text "PlaytimeTxt", 200, 130, "", 0, 1, 561
Comment: @write_text "PlaytimeValue", 236, 130, "", 0, 1, 561
Comment: @write_text "PlaytimeHH", 236, 130, "", 0, 0, 561
Comment: @write_text "PlaytimeMM", 236, 130, "", 0, 0, 561
Comment: @write_text "PlaytimeSS", 236, 130, "", 0, 0, 561

Main event: (Parallel Process or Autostart depending on what you're using it for)

Comment: @change_text "PlaytimeTxt", "Time:", 1
Branch if Var [4007:Time-PlaytimeHH] is 10 Less
<>Comment: @change_text "PlaytimeValue", " : :", 1
<>Comment: @change_position "PlaytimeMM", 236, 130
<>Comment: @change_position "PlaytimeSS", 236, 130
<>
Else Handler
Branch if Var [4007:Time-PlaytimeHH] is 100 Less
<>Comment: @change_text "PlaytimeValue", " : :", 1
<>Comment: @change_position "PlaytimeMM", 242, 130
<>Comment: @change_position "PlaytimeSS", 242, 130
<>
Else Handler
<>Comment: @change_text "PlaytimeValue", " : :", 1
<>Comment: @change_position "PlaytimeMM", 248, 130
<>Comment: @change_position "PlaytimeSS", 248, 130
<>
End
<>
End
Comment: @change_text "PlaytimeHH", "\v[4007]", 0
Branch if Var [4008:Time-PlaytimeMM] is 10 Less
<>Comment: @change_text "PlaytimeMM", " 0\v[4008]", 0
<>
Else Handler
<>Comment: @change_text "PlaytimeMM", " \v[4008]", 0
<>
Branch if Var [4009:Time-PlaytimeSS] is 10 Less
<>Comment: @change_text "PlaytimeSS", " 0\v[4009]", 0
<>
Else Handler
<>Comment: @change_text "PlaytimeSS", " \v[4009]", 0
<>

For now, this will at least get the playtime into easily usable variables. Once I figure out how to display it in the main menu, I'll post the final version.
Pretty sweet. You could probably make this do able to do a Chronomancy attack too with a mirror variable that can be reset.

Is it running from a New Game? Or a new save?

I mean, if I do the Save Early, Save Often rule and after starting game 1, playing for fifteen hours, I get to a big dungeon, and want to save there at hour 21. Since it is a new save, but the same game, does this make it 21:00? Or 6:00 since this is a new save?
Each point between loading a game (or starting a new one) and a save point is considered a "session." Fear not. They add up appropriately. Read the third paragraph in my previous post. :)

In your example, it would say 21:00.
Ah, I thought so. Can you make on that counts the number of steps as well?
author=bulmabriefs144
1/3 transp, 1/2 transp, and semi-transparent on tile types doesn't work either.


I was wondering why that seemed to have stopped working! At first I thought there was something wrong with the tiles/sprites I was using. I too humbly ask for a fix to this, whenever it's convenient (as it's not likely that my game will be finished any time soon anyway!)
Cherry is (gradually) updating DynRPG. It should have transparency fixed (it was commonly mentioned) along with alot of new functions. I'd like some way of telling which item/skill has been used, but that might not be the next update.
Do you mean on the map? Or in battle?

Because in battle you can already get this info easily: onDoBattlerAction/onBattlerActionDone, check the RPG::Action class: http://rpg-maker.cherrytree.at/dynrpg/class_r_p_g_1_1_action.html
I wouldn't say easily. I dunno the correct syntax, so I get stuck typing something like

if(RPG::AK_SKILL == 115)

And wondering why it doesn't work. Possible, yes, but I'd not say easy.

It should just be a matter of looking that up, and turning on a switch afterwards.
AK_SKILL is just used to detect if an actor used the "Skill" command (as it's an enum). It's not an array for the actual skills. I believe you have to use:
if(battler->action->skillId = 115) {
Well, "easy" means "easy for people who know C++" of course.

if(battler->action->kind == RPG::AK_SKILL && battler->action->skillId == 115)
Hey you, I know some C++ (beginner C++ in high school; I'm now 30). But somehow, I never learned how to use -> . *pointers or namespaces, so that sorta thing confuses me.

I'm gonna try it. Can't promise anything though.

Haven't tried to build yet, but I wanna run this by you.


#define AUTO_DLLMAIN
#include <DynRPG/DynRPG.h>
#include <iostream>
#include <string>
using namespace std;

std::map<std::string, std::string> configuration;



bool onStartup(char *pluginName) {
// We load the configuration from the DynRPG.ini file here
configuration = RPG::loadConfiguration(pluginName);
return true; // Don't forget to return true so that the start of the game will continue!
}

bool onComment( const char* text,
const RPG::ParsedCommentData* parsedData,
RPG::EventScriptLine* nextScriptLine,
RPG::EventScriptData* scriptData,
int eventId,
int pageId,
int lineId,
int* nextLineId )
{
std::string cmd = parsedData->command;


if(!cmd.compare("item_id"))
{
int ItemAmt = parsedData->parameters[0].number;
int ItemVar = parsedData->parameters[1].number;
int ItemSwitch = parsedData->parameters[2].number;

RPG::variables[ItemVar] = ItemAmt; //feels very roundabout, but I'm rusty

return false;
}
if(!cmd.compare("skill_id"))
{
int SkillAmt = parsedData->parameters[0].number;
int SkillVar = parsedData->parameters[1].number;
int SkillSwitch = parsedData->parameters[2].number;

RPG::variables[SkillVar] = SkillAmt;

return false;
}

return true;
}

//I'm REALLY doubtful this passes to the ActionDone

bool onBattlerActionDone ( RPG::Battler * battler,
bool success )
{
if(battler->action->kind == RPG::AK_SKILL && battler->action->skillId == RPG::variables[SkillVar])
{
RPG::switch[SkillSwitch] = true;
}
else
{
RPG::switch[SkillSwitch] = false;
}

if(battler->action->kind == RPG::AK_ITEM && battler->action->itemId == RPG::variables[ItemVar])
{
RPG::switch[ItemSwitch] = true;
}
else
{
RPG::switch[ItemSwitch] = false;
}

return true;
}

I'm almost certain these variables do not pass properly into the ActionDone, and I also want to reset to zero things after checking (so it isn't stuck on whatever you enter). Yep, I was right.

Pfft, I meant switches not switch.
But somehow, I never learned how to use -> . *pointers or namespaces, so that sorta thing confuses me.

So you don't really know C++. It's like "I know some cooking but I have no idea of boiling things". I would recommend you to take some tutorials about pointers and about object-oriented programming in C++! I think all these things will make much more sense then. From what I saw until now, it looks to me like you are often just poking around with trial and error and if something works, you cannot 100% be sure why, which also means you overlook mistakes which make you code not instantly fail but have other sideeffects.

You have to declare your SkillVar, etc. globally.
http://www.learncpp.com/cpp-tutorial/42-global-variables/

But I'm an expert at frying. :)

I did, they routinely went over my head.

The other stuff, I got instantly (KazString is full of files, arrays, strings, etc), but certain things didn't stick, (with pointers, I couldn't really grasp the difference between -> and *, except that * seems to work one making a sort of pointer variable, and -> points to another file or variable (but I'm not sure of the rules of when it can/can't do so though). With . and the :: namespace it was knowing the extensive terms, as I got that . was sort of for commands (yes, I know it has a name other than commands, but I see it all the time being used for file.open or somesuch.delete or str.copy and even used it a couple times) but I didn't know all or even that many of the commands. And here, I see stuff like RPG::Action or RPG::Hero but then it turns out I instead needed to do the above,

if(battler->action->kind == RPG::AK_SKILL && battler->action->skillId == 115)

or for RPG::Hero to get the x

RPG::hero->x;

which didn't seem to be explained anywhere in the many many DynRPG tutorials I read over and over. Having example codes for each would be a great help...)

Yea, I know about global variables. I've had to use them half the time, because I get "variable is not in scope" error routinely.

But there's a problem here.

These are used inside the comments and then inside the battle action done. They get defined there in relation to getting defined.

Or do you want me to just put

int SkillAmt;

and such as global, and then remove the int from the onComment part?

Also, after I check the action done, I want a run-once option. Meaning I don't continue checking every turn for the variable, which is probably still active?

http://rpgmaker.net/media/content/users/3388/locker/BattleID.rar

YAY! It works.
author=bulmabriefs144
which didn't seem to be explained anywhere in the many many DynRPG tutorials I read over and over. Having example codes for each would be a great help...)


The reason why there isn't is because the tutorials assume you know C++, which is a pretty reasonable assumption to make in this context. You're troubles isn't with DynRPG itself, but rather with the language.

As I told you long time ago, and Cherry now as well. You should take another look at some C++ tutorials (preferably ones noted as introductory ones), and then just go through it and make programs not related to DynRPG in the first run to get down the basics, in particular pointers and classes, which seems like something you keep struggling with.

' . ' and ' -> ' is actually the same thing, except that the latter dereferences a pointer before trying to access the member.
that is RPG::hero->x is equivalent with (*RPG::hero).x.
It's not a matter of one is for variables and other for methods (what you called commands), and this is the kind of stuff which is "fairly" basic C/C++ knowledge. If this sounds cryptic to you, then you should, as said, go read some tutorials. It's simply the best way rather than just trial and error. Experimenting like you do should come once you've aquired the basic concepts needed
Btw, despite having both skill_id and item_id virtually identical, only item ID works. So I'm just gonna make it item-centered, and remove the skill_id.
I don't suppose I could enlist the aid of someone to make a slight change to a plugin for me?

I need the condition_icons to draw 24 pixels above battlers instead of the default 48. I thought this would be a simple enough change that even I could do it, and changing the actual code is as simple as changing the 48 to a 24.

However, installing codeblocks, configuring it properly and then going through the "hello world" tutorial linked above took me almost 3 hours. And after all of that, I couldn't get the damned thing to compile ANYTHING, spewing an error that my toolchain path was probably not set right - which I can see, because I literally only did what cherry told me to in the tutorial without knowing anything about what I was actually doing.

Anyways, if someone could change that and link me to the modified .dll file, that'd be awesome. Or help me figure out why nothing will compile for me in code::blocks, that'd probably be even better.


"are_you_sure - Release" uses an invalid compiler. Probably the toolchain path within the compiler options is not setup correctly?! Skipping...
Nothing to be done.

I don't want it to seem like I'm being an idiot here, but I managed to fix the problem, thanks to many minutes of google-fu, and it turned out the problem was that the code::blocks installer with the minGW compiler included with it, incorrectly sets the default path of MinGW to c:\minGW which was not where it was installed by default, meaning the compilers could not be found.

I don't think I'll need help with this anymore. I should bee good to fiddle around on my own now.
Are you using GCC compiler version 4.6.1? Any version after that doesn't work with DynRPG yet, and will give you compile issues. You also need to make sure "DynRPG" is linked to your project. In the getting started page, it's these steps:
17. Open the Project menu, select Build options....
18. Go to the Linker settings tab.
19. At the Link libraries section, click Add.
20. Enter DynRPG and click OK.
21. Click OK again.
You have to do this any time you start a new project.


For the battle conditions code, I think you would just modify these line:

Heroes:
topY = battler->y - 48 / 2;

Monsters:
topY = monster->y - monster->image->height / 2;

You should be able to just subtract an additional offset value, so you'd end up something like this:
topY = (battler->y - 48 / 2) - 8;
topY = (monster->y - monster->image->height / 2) - 8;

Which should move the image up 8 pixels.
Can someone make a LoadGame plugin? Something where you can assign variables with a random number roll of some sort, to make a "different every time" deal. Somehow you set up what the min and max range is, but yea, I think they used this thing in Final Fantasy X (those random chests got reverted on save in the Omega Zone, and load differently for each reload). That or something where it turns on a switch (that you can set to common event), and from there make some sort of random number roll or special event. You could also have it run a different switch after save games.

If should be fairly simple, but my last few C++ codes have failed for no reason I can discern.


include the libraries time.h and stdlib.h,
use the onInitFinished callback and write the line "srand(time(NULL))" in it.

now that this is done, the rand() function will work fine.
So simply use the loadGame callback and write something like

RPG::variables[69] = rand()%100;


This will write a value between 0 and 99 into variable 69
I'm not entirely sure if this will work though, since the game variables might not have been loaded yet at this point. You might have to just set a boolean variable to true, which waits until you're physically ingame, and then set the random variable once.

The above mentioned should be the only difficulties though