Sorry your browser is not supported!

You are using an outdated browser that does not support modern web technologies, in order to use this site please update to a new browser.

Browsers supported include Chrome, FireFox, Safari, Opera, Internet Explorer 10+ or Microsoft Edge.

DarkBASIC Professional Discussion / Cross-platform DBPro reimplementation

Author
Message
Memorix101
5
Years of Service
User Offline
Joined: 14th Feb 2016
Location:
Posted: 29th Sep 2019 17:59
Back in 2017, I've got the idea to do a cross-platform reimplementation of DBPro like MonoGame for XNA.
I've worked on it for a weekend and put it on hold since then.

However, I open-sourced it in the hope to find some people who are interested to support me and commit to it, because it's a lot of work to implement all DBPro commands myself.

The goal is to build a cross-platform compiler to compile DB/DBPro code for Windows, Linux, Mac and other platforms.

https://gitlab.com/Memorix101/darkgamekit


tboy
8
Years of Service
User Offline
Joined: 1st Jan 2013
Location:
Posted: 29th Sep 2019 21:43
Hi Memorix,

I think this is a cool idea and well worth pursuing, even if it's just for the experience of creating a product of this magnitude.

I know TGC have GameGuru and AppGameKit but I think they are well overdue a new DBPRO perhaps call it DarkBasicX (X for cross platform) and this
could provide them the start they need. I realise there are many different products now to choose from but I truely believe DBPRO resonates
with many people and will use it regardless of the competition.

I'll keep an eye on this project and help out when and if I can.

Best of luck!
Memorix101
5
Years of Service
User Offline
Joined: 14th Feb 2016
Location:
Posted: 30th Sep 2019 09:03
Hi,

DBPro was one of the first things that got me into programming when I was a child.
I started programming at the age of 10 years.
I love those little games and their old graphics style.
The thought that all of this would be kinda lost makes me sad.
Sometimes when I find old code in the TGC magazines it even doesn't work on actual Windows OSes anymore because DirectX has changed.

This project could work for any platform that raylib supports: Desktop, Raspberry Pi, Android, WebGL.
I rewrote it so many times. I started with SDL2 and OpenGl at first. Then changed it to a different engine and finally changed it to raylib because it's so much handier than SDL2 and OpenGL code.

Currently, I'm implementing all the base commands and try to get the audio and 2D part working.
Brian Lancaster
7
Years of Service
User Offline
Joined: 20th Dec 2013
Location: Oakland, CA
Posted: 8th Feb 2020 02:51
Holy crap, please let this come to fruition. I would love for Brigand: Oaxaca to run on Linux. I switched to AppGameKit for my next project and it forces me to use sprites instead of just pasting images. Anything I can do to promote it online?
TheComet
13
Years of Service
User Offline
Joined: 18th Oct 2007
Location: I`m under ur bridge eating ur goatz.
Posted: 17th Feb 2020 19:38 Edited at: 17th Feb 2020 19:41
Hi @Memorix101

It's funny that I found this because I just started working on a cross platform DBP compiler myself. Mostly for the sake of learning more about parsers and compilers.
https://github.com/thecomet/opendarkbasic

Hit me up, maybe we can combine our codebases. My discord is TheComet#5387.

From a quick glance at your repo it looks like you've started reimplementing the SDK, which is something I've not started. Well, I see a lot of stubs, but that's more than what I've got!

I'm about 80% done with the parser. I still need to add support for function and subroutine definitions, UDTs, arrays, pointers, and commands. There are probably a few other obscure things I've forgotten about, but I've got enough DB code to throw at it to find almost everything.

For those interested in how one would approach something like this, I can go into a bit more detail on what I've done so far.

The parser is built using Flex and Bison. Flex is a lexical analyzer generator, which lets you specify a set regular expression rules that get matched against your input text to produce tokens. These are most of the rules for DarkBASIC:
https://github.com/TheComet/OpenDarkBASIC/blob/master/odb-compiler/src/Scanner.lex#L29

Bison lets you specify the language's syntax using an input grammar, which is a set of rules that it tries to match against the tokens produced by the Flex lexer. You can see the grammar for DarkBASIC here:
https://github.com/TheComet/OpenDarkBASIC/blob/master/odb-compiler/src/Parser.y#L139

The result is that something like this:


Gets converted into a structure of relationships between each token, also known as a "(abstract) syntax tree" or AST:



Here is a more complex example:


https://forum.thegamecreators.com/attachment/85329

Once you have the AST it's easy to manipulate it to do e.g. optimizations or to match references. It's also fairly straight forward to evaluate the program (interpret it) or use it to generate machine code.

The graphics above were generated by dumping the AST structure to DOT format and using graphviz to convert it to an image.
"Jeb Bush is a big fat mistake" -- Donald Trump
https://vt.tumblr.com/tumblr_o2rvwdLLSF1rmjly4.mp4

Attachments

Login to view attachments
TheComet
13
Years of Service
User Offline
Joined: 18th Oct 2007
Location: I`m under ur bridge eating ur goatz.
Posted: 20th Feb 2020 21:06 Edited at: 20th Feb 2020 21:09
I guess I'll start posting updates in this thread? Sorry @Memorix101 if you don't want me to I can make my own thread

The parser now supports function calls, function declarations, gosub, subroutine declarations, and UDTs. It does not support goto and commands are still not fully working.

I wrote a parser which can load the original keyword.ini files and build a dictionary of keywords. This is necessary because otherwise statements such as the following would be too ambiguous to parse:


Or


I also wrote a CLI for interfacing with the compiler. This is what it looks like:



I've tried parsing iced.dba from the DBC samples and it gets about 90% of it right, which is a very good sign.

Here's the link to the github repo if you want to try and compile/run it for yourself. I'm developing it on linux but if you install Flex and Bison it will also work on Windows.
https://github.com/thecomet/opendarkbasic
"Jeb Bush is a big fat mistake" -- Donald Trump
https://vt.tumblr.com/tumblr_o2rvwdLLSF1rmjly4.mp4

Attachments

Login to view attachments
TheComet
13
Years of Service
User Offline
Joined: 18th Oct 2007
Location: I`m under ur bridge eating ur goatz.
Posted: 23rd Feb 2020 04:42 Edited at: 23rd Feb 2020 04:43
I hit a milestone today. I was able to parse iced.dba, one of the original DBC samples. Here's the AST overview:



You can also click here to look at the SVG in your browser: https://forum.thegamecreators.com/attachment/85353

I went through manually and validated it as best as I could, and as far as I can tell, there's only some minor issues with operator precedence. For instance, this code


Looks like this in the AST:


Which translates back to:
"Jeb Bush is a big fat mistake" -- Donald Trump
https://vt.tumblr.com/tumblr_o2rvwdLLSF1rmjly4.mp4

Attachments

Login to view attachments
TheComet
13
Years of Service
User Offline
Joined: 18th Oct 2007
Location: I`m under ur bridge eating ur goatz.
Posted: 3rd Mar 2020 19:13
I exhaustively tested all operators in DBP to figure out their precedence. Here they all are ordered lowest to highest:


The program I used to do this is here:


For example, if ^ has a higher precedence than / then this program will print "bca". Otherwise it will print "abc". This lets you test all operators and construct a sorted list, which I can then use to implement the grammar correctly.

DBP's operator precedence rules are a bit unusual. First off, they don't have operators with equal precedence. For example, + and - in most languages are usually treated equally strong, but in DBP, minus will bind first. This is true for all operators you might think are equal, like << and >>, or <> and =.

It is also strange that equals is stronger than all bitwise operators except for bitshift.

Anyway, my parser now follows the precedence rules of DBP exactly. I obviously have written unit tests to check for this:



I tried parsing an old game of mine called LightShip to see how fast it is, and I can process about 6k lines in 10ms without optimizations. So I'm fairly happy:



Select/case statements are also implemented, and so is goto.
"Jeb Bush is a big fat mistake" -- Donald Trump
https://vt.tumblr.com/tumblr_o2rvwdLLSF1rmjly4.mp4
darkdomy
18
Years of Service
User Offline
Joined: 6th Apr 2003
Location: Italy
Posted: 13th May 2020 02:49 Edited at: 13th May 2020 03:01
hallo very cool Woow

opendarkbasic this program a similar BCX converts BASIC source code to C/C++ ???

a convert darkbasic/darkbasicpro to c/c++ ??

darkgamekit is a different DarkGDK ? (DarkGDK or SDK ? ? a use a C complier visual studio ? )

I'm waiting for info

tanks
TheComet
13
Years of Service
User Offline
Joined: 18th Oct 2007
Location: I`m under ur bridge eating ur goatz.
Posted: 29th May 2020 19:28 Edited at: 29th May 2020 19:28
Quote: "opendarkbasic this program a similar BCX converts BASIC source code to C/C++ ???

a convert darkbasic/darkbasicpro to c/c++ ??"


DarkBASIC to executables.

There are two parts in this project: The language compiler and the runtime (DarkBASIC SDK).

The goal of this project's compiler is to produce an LLVM intermediate representation, which we can then use to cross compile to a target platform.

The goal of the SDK is to reimplement DarkBASIC Pro's commands using modern graphics APIs (DX12, OpenGL, maybe Vulkan? haven't decided yet)

This diagram might help you understand more:

"Jeb Bush is a big fat mistake" -- Donald Trump
https://vt.tumblr.com/tumblr_o2rvwdLLSF1rmjly4.mp4

Attachments

Login to view attachments
gosukiwi
AGK Tool Maker
User Offline
Joined: 24th May 2020
Location: Argentina
Posted: 25th Jul 2020 19:06
Looks really impressive!
GOTO HelloWorld!
7
Years of Service
User Offline
Joined: 21st Oct 2013
Location: Skyrim,...and lost in it!
Posted: 27th Aug 2020 16:37
The Comet

Posted: 29th May 2020 19:28 Edited at: 29th May 2020 19:28

You used a program to create this diagram? I would like to know which one it is please. That seem very useful to establish a program logic visually!

And what a program you are creating here! Amazing! I wish i would understand a word of what this is about! Very impressive indeed!
TheComet
13
Years of Service
User Offline
Joined: 18th Oct 2007
Location: I`m under ur bridge eating ur goatz.
Posted: 3rd Nov 2020 13:13
Quote: "You used a program to create this diagram? I would like to know which one it is please. That seem very useful to establish a program logic visually!"


For the diagrams I had my compiler output the AST to DOT (https://en.wikipedia.org/wiki/DOT_(graph_description_language). Then you can use graphviz to convert it into an image or PDF.
"Jeb Bush is a big fat mistake" -- Donald Trump
https://vt.tumblr.com/tumblr_o2rvwdLLSF1rmjly4.mp4
TheComet
13
Years of Service
User Offline
Joined: 18th Oct 2007
Location: I`m under ur bridge eating ur goatz.
Posted: 16th Dec 2020 17:44
We've slowly been making progress on ODB (OpenDarkBASIC). Most notably, @dga was able to load the original DBPro DLLs from LLVM IR and generate the correct calls to display a cube:



We plan to support the original TGC DBPro SDK first (which will run on Windows only for now) and then the plan is to build a new SDK using more modern graphics APIs.

A major obstacle we faced was how do we load keywords? In order to parse the language, you must have a full list of all possible keywords ahead of time, otherwise you won't be able to resolve ambiguous statements. Further, you must also know the type information for each command (how many arguments are there? What types are those arguments?) And lastly, you must know which keyword came from which DLL so that LLVM can link against that DLL when you eventually run your program.

DBPro approached this problem by storing the keyword strings inside each DLL in a resource table. Unfortunately, this is a Windows only feature, so for ODB, we needed to be a little more general.

The approach for ODB plugins currently looks like the following:



We store type information, help strings, and the keyword string in global variables. When you run the ODB compiler, it will scan for all plugin DLLs and try to load symbols that match ".*_keyword", from which it can then load the proper keyword, before parsing your DBA source files. Making this process not only cross-platform, but also dependent on the SDK type (either TGC DLLs or ODB DLLs) was definitely a challenge.

Another thing I worked on was better error reporting, so if you write a plugin that has malformed typeinfo, or if your plugin tries to define a command that already exists in another plugin, the ODB compiler will tell you exactly what went wrong and where:



The next big step will be to transform the AST into LLVM IR, which is the final piece of the puzzle before we can compile DBP code into machine code.

If you are interested in following the development process more closely, or if you are looking to be a user of ODB at some point, or if you want to help us out, feel free to join our discord server. This is our main communication channel.
https://discord.com/invite/vVH7Te4

"Jeb Bush is a big fat mistake" -- Donald Trump
https://vt.tumblr.com/tumblr_o2rvwdLLSF1rmjly4.mp4
LBFN
14
Years of Service
User Offline
Joined: 7th Apr 2007
Location: USA
Posted: 24th Dec 2020 15:44
Looking very cool. I don't know how you know all of this stuff, but it is very impressive! Good luck with the project.



So many games to code.....so little time.
wattywatts
11
Years of Service
User Offline
Joined: 25th May 2009
Location: Michigan
Posted: 4th Jan 2021 22:28
This looks pretty cool TheComet! I can't imagine the amount of work getting around DirectX.
TheComet
13
Years of Service
User Offline
Joined: 18th Oct 2007
Location: I`m under ur bridge eating ur goatz.
Posted: 7th Jan 2021 11:48
Quote: "Looking very cool. I don't know how you know all of this stuff, but it is very impressive! Good luck with the project."


Thanks a lot, we'll need all the luck we can get! A lot of this stuff is new territory for me, but I've dealt with similar topics in previous projects so I don't feel completely lost either (I know generally what I need to do and where I need to go).

Quote: "This looks pretty cool TheComet! I can't imagine the amount of work getting around DirectX."


Yeah it will be a lot of work. That's why we've decided to use the original TGC DLLs first and just work on the language for the time being.
"Jeb Bush is a big fat mistake" -- Donald Trump
https://vt.tumblr.com/tumblr_o2rvwdLLSF1rmjly4.mp4
TheComet
13
Years of Service
User Offline
Joined: 18th Oct 2007
Location: I`m under ur bridge eating ur goatz.
Posted: 5th Feb 2021 13:29 Edited at: 5th Feb 2021 13:40
@dga was able to make good progress on codegen. We are now at a point where we can fully compile a DBP program into an executable on Windows. Here's a little skybox demo written in DBP compiled with ODB:



I'm currently working on improving our log output to produce good looking error messages:



There's still quite a bit of work left here. Depending on the type of syntax error (especially nesting errors) it will sometimes point to a completely irrelevant section of code.

Apart from this, I've been doing a lot of cleaning up, refactoring and overall improvements on our codebase.

I expect (hope!) that we will be able to release an alpha build of this project within the next few months.
"Jeb Bush is a big fat mistake" -- Donald Trump
https://vt.tumblr.com/tumblr_o2rvwdLLSF1rmjly4.mp4
tarkusAB
4
Years of Service
User Offline
Joined: 15th May 2016
Location: Tokyo, Japan
Posted: 8th Feb 2021 00:57
Quote: "I expect (hope!) that we will be able to release an alpha build of this project within the next few months."


Awesome to hear. What platforms do you expect this will be able to export to? Sorry I don't know much about compilers or LLVM.
Ortu
DBPro Master
13
Years of Service
User Offline
Joined: 21st Nov 2007
Location: Austin, TX
Posted: 8th Feb 2021 22:18
Interesting project TheComet, I'll keep watching
http://games.joshkirklin.com/sulium

A single player RPG featuring a branching, player driven storyline of meaningful choices and multiple endings alongside challenging active combat and intelligent AI.
TheComet
13
Years of Service
User Offline
Joined: 18th Oct 2007
Location: I`m under ur bridge eating ur goatz.
Posted: 13th Feb 2021 01:09 Edited at: 13th Feb 2021 01:25
Quote: "What platforms do you expect this will be able to export to?"


Windows, OSX and Linux. Alpha build will be for Windows.

Come to think of it, I don't think it'd be too much additional work to support browsers, Android and iOS too, but we'll see. It all depends on which graphics API we choose to use.

I'm actually thinking about dropping OSX because they're being real anal with the graphics APIs they want to support. OSX is removing support for OpenGL and they don't want to support Vulkan because they're trying to promote their own called "Metal".
Vulkan would be the best choice because it's supported by everything (Windows, Linux, Android, browser) except, of course, Apple devices.


I've been working a lot on logging and formatting. Here's another nice example of the error you would see if you had a select/case statement with more than 1 default case:



I've started working on some continuous integration stuff, too. We need a way to systematically compare how DBP and ODB compile/run code to make sure that we are as compatible as we can be to DBP. It also helps ensure that ODB is working as expected.

The idea is to create a bunch of code snippets that are compiled on both DBP and ODB and then compare the results. You obviously don't want to do this manually, so we needed a way to run DBP and ODB on different platforms automatically. I figured the easiest way would be to reate web interfaces for DBP and ODB and then it would be easy to set up a service that automatically compiles and compares snippets:



Here's an example of sending the code stdout "hello world" to 127.0.0.1:801/compile (the DBP web API is running at this address) and receiving a result:



You can see that it compiles the code, executes it, and responds with whatever the program output.

That might be a bit hard to understand for some, so here's the same thing but through discord. We have a bot called odb-bot that can send the request and format the response for us:



stdout is a custom command we added to DBP. It does the same thing as print, except it writes to standard out instead of to the screen. This makes it easier to get output from DBP.
"Jeb Bush is a big fat mistake" -- Donald Trump
https://vt.tumblr.com/tumblr_o2rvwdLLSF1rmjly4.mp4
Ortu
DBPro Master
13
Years of Service
User Offline
Joined: 21st Nov 2007
Location: Austin, TX
Posted: 13th Feb 2021 06:02
Eff apple and osx. They have always preferred to silo themselves and have no interest in cross platform. Go with vulkan.
http://games.joshkirklin.com/sulium

A single player RPG featuring a branching, player driven storyline of meaningful choices and multiple endings alongside challenging active combat and intelligent AI.
Unseen Ghost
18
Years of Service
User Offline
Joined: 2nd Sep 2002
Location: Ohio
Posted: 16th Feb 2021 20:49
Keep up the good work, I'm definately looking forward to this project. I would love to be a Alpha Beta tester
Gigabyte Board/2.93Ghtz Intel Core Duo Proc./4GB Ram/Nvidia Geforce 730 2GB/1TB Western Dig. SSD/Windows 10 Home/Dark Basic Pro 9Ex

No one cares how much you know until they know how much you care.
TheComet
13
Years of Service
User Offline
Joined: 18th Oct 2007
Location: I`m under ur bridge eating ur goatz.
Posted: 19th Feb 2021 03:26 Edited at: 19th Feb 2021 03:29
We've now got continuous integration (CI) tests up and running, so whenever we make changes to OpenDarkBASIC and push them to github, CI will automatically build a new version ODB, compile/run all of the test code snippets on it and compare them with DBP. The results are posted to our Discord so we see them immediately:



Right now we only have 6 tests, so it's not very telling of how stable ODB is, but as we discover bugs our test suite will get larger and larger.

I've continued to work on message formatting. Specifically, I spent some time formatting the help output when you run odbc with no arguments, as this is probably the first thing anyone will see when first using it and first impressions matter:



You can of course disable color output with the --no-color option and get rid of the banner at the top with the --no-banner option, which you can see on the right.
"Jeb Bush is a big fat mistake" -- Donald Trump
https://vt.tumblr.com/tumblr_o2rvwdLLSF1rmjly4.mp4
TheComet
13
Years of Service
User Offline
Joined: 18th Oct 2007
Location: I`m under ur bridge eating ur goatz.
Posted: 23rd Feb 2021 23:56 Edited at: 23rd Feb 2021 23:58
We have two exciting new features coming to ODB.

New Math types

Given that DBP is a language designed for making games, it makes sense to include vector, matrix and quaternion types and operators as part of the language's builtin types. Our compiler can make use of SIMD to make operations on these types blazingly fast. The following list of types is now supported by the parser:



The standard binary operators can be used to do math with these types, and there will also be some additional special operators such as cross, dot, inv det or conj. Examples:


Modifying values in these types can be done using the same syntax you'd use for UDTs:


For quaternions and complex numbers the parser also supports complex and quaternion literals:


New initializer syntax

One of the annoying things I found with DBP is the inability to initialize UDTs on the same line. The parser now lets you write the initial values you want inside a UDT declaration:


It is also possible to use initializer lists when defining UDT variables:


This syntax goes much further than the above. For instance, you can initialize arrays that are inside nested UDTs:


It's also possible to pass initializer lists to functions:
"Jeb Bush is a big fat mistake" -- Donald Trump
https://vt.tumblr.com/tumblr_o2rvwdLLSF1rmjly4.mp4
James H
13
Years of Service
User Offline
Joined: 21st Apr 2007
Location: St Helens
Posted: 24th Feb 2021 02:45
Oh my, exciting times Presumably pre-existing plugins would not work? Also what kind of price will it be?

Win 7 Pro 64 bit SP1, AMD A4-5300 APU 3.4GHz, 8GB DDR3, NVidia GeForce GTX 750 1GB GDDR5, ASUS A55BM-E
MadBit
Valued Member
Gold Codemaster
11
Years of Service
User Offline
Joined: 25th Jun 2009
Location: Germany
Posted: 24th Feb 2021 04:52
You guys are so awesome.
These are all things I miss about DBPro and Agk.
What is the plan for the underlying graphics engine?
Will it be raylib as the thread was started? Or will another one be taken?
Maybe the Wicked engine to catch up with GameGuru.
Or do you have a completely different idea?

In any case, keep up the good work. I'm really curious what else will come out of it.
Share your knowledge. It\'s a way to achieve immortality. (Tenzin Gyatso)
TheComet
13
Years of Service
User Offline
Joined: 18th Oct 2007
Location: I`m under ur bridge eating ur goatz.
Posted: 24th Feb 2021 07:20
Quote: "Presumably pre-existing plugins would not work?"


They do work, if you tell odbc to use the DBPro SDK (odbc --sdktype dbpro)

Quote: "Also what kind of price will it be?"


It's an open source project so the answer is it's free. We could set up a Patreon maybe, or try to get funding through Kickstarter to develop it further, or something along those lines. Haven't thought about this much.

Quote: "What is the plan for the underlying graphics engine?"


We're leaning towards Vulkan at this point.

ODB supports the original DBPro engine as well which means it will behave exactly like DarkBASIC Pro except it'll run a lot faster. This will only work on Windows, though.

"Jeb Bush is a big fat mistake" -- Donald Trump
https://vt.tumblr.com/tumblr_o2rvwdLLSF1rmjly4.mp4
Ortu
DBPro Master
13
Years of Service
User Offline
Joined: 21st Nov 2007
Location: Austin, TX
Posted: 27th Feb 2021 18:12
Nice! This is getting exciting!

I've got to say though, everytime i see odbc I think of the database connector and have a moment of confusion
http://games.joshkirklin.com/sulium

A single player RPG featuring a branching, player driven storyline of meaningful choices and multiple endings alongside challenging active combat and intelligent AI.
TheComet
13
Years of Service
User Offline
Joined: 18th Oct 2007
Location: I`m under ur bridge eating ur goatz.
Posted: 1st Mar 2021 15:07 Edited at: 1st Mar 2021 15:12
Quote: "everytime i see odbc I think of the database connector and have a moment of confusion"


Yeah it's an unfortunate choice for a name. I wasn't aware of open database connectivity. Any suggestions for a different name?

I chose "odbc" because conventionally, compilers use the "c" suffix like in "javac" or "rustc" or "cc". And "odb" is short for "OpenDarkBASIC".

Maybe "odbac"? "odba-compiler"? "odb-compiler"?
"Jeb Bush is a big fat mistake" -- Donald Trump
https://vt.tumblr.com/tumblr_o2rvwdLLSF1rmjly4.mp4
MadBit
Valued Member
Gold Codemaster
11
Years of Service
User Offline
Joined: 25th Jun 2009
Location: Germany
Posted: 10th Mar 2021 04:51
TheComet wrote: "We're leaning towards Vulkan at this point."

May I point your attention to this project (Diligent Engine) (here's the github page)? I don't know if you already know this one and have already discarded it for some reason.
But I think this engine has its advantages. It would handle DX12, Vulkan, OpenGL and Metal.
As a bonus, as I understand it, the HLSL shaders could also be used.
Share your knowledge. It\'s a way to achieve immortality. (Tenzin Gyatso)
MadBit
Valued Member
Gold Codemaster
11
Years of Service
User Offline
Joined: 25th Jun 2009
Location: Germany
Posted: 10th Mar 2021 04:51 Edited at: 10th Mar 2021 04:52
TheComet wrote: "We're leaning towards Vulkan at this point."

May I point your attention to this project (Diligent Engine) (here's the github page)? I don't know if you already know this one and have already discarded it for some reason.
But I think this engine has its advantages. It would handle DX12, Vulkan, OpenGL and Metal.
As a bonus, as I understand it, the HLSL shaders could also be used.


Sorry double post.
Share your knowledge. It\'s a way to achieve immortality. (Tenzin Gyatso)

Login to post a reply

Server time is: 2021-04-10 16:24:08
Your offset time is: 2021-04-10 16:24:08