Code Monkey home page Code Monkey logo

tsc's Introduction

The Secret Chronicles of Dr. M.

“The Secret Chronicles of Dr. M.” is a 2D sidecrolling platform game, with a rich set of graphics, music, and an advanced level editor that allows you to create your own levels. The level editor allows for in-game scripting so there are no borders apart from your imagination.

The project is a fork of SMC, which is not developed actively anymore. Note this is not merely a continuation of SMC, but we have our own goals and design principles we are slowly integrating into both the codebase and the artwork.

How to install?

Releases are published precompiled for Windows at the website. If you want to compile TSC yourself, please see the INSTALL.md file.

Links

Contributing

Any contributions to the code, the graphics, the music, etc. are greatly appreciated. However, before starting your work on the game, please consider the following:

  • You have to be familiar with at least the basics of using the Git version control system. This can be achieved by reading the first two chapters of this great online Git book. Also reading chapter 3 is highly recommended as we use branches all the time.
  • If you want to contribute code, please read the coding conventions document in tsc/docs/pages/conventions.md.
  • If you want to contribute artistic work, please read the styleguide
  • If you specifically target issues from the issue tracker, please use “fixes #43” for bug tickets you fix and “closes #43” for other tickets you resolve as part of the message in your commits. This causes GitHub to automatically close the corresponding ticket if we merge your changes.

Custom local configurations are provided for Emacs and ViM. In order for local ViM configurations to work, you will need the localvimrc plugin, which can be installed with the following command on most Bourne-compatible shells:

mkdir -p ~/.vim/plugin
cd ~/.vim/plugin
wget https://raw.githubusercontent.com/embear/vim-localvimrc/master/plugin/localvimrc.vim

License

TSC is a two-dimensional jump’n’run platform game.

Copyright © 2003-2011 Florian Richter

Copyright © 2012-2019 The TSC Contributors

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

  • See COPYING for the full license text.
  • See tsc/docs/authors.txt for the full list of authors.

Graphics, music, and any other artistic content in the game is not licensed under the GPL. These assets undergo different terms as outlined as follows: they are normally licensed under some kind of CC license, as specified by an accompanying .txt or .settings file to an asset that gives both the author(s) and the license of the asset in question. Those assets whose accompanying .txt or .settings file does not specify a license are licensed under the old SMC Contribution license, which is included as the file tsc/docs/pages/old_smc_contribution_license.md. Those assets were inherited from SMC when TSC was forked off it, and we are looking for a graphics artist to replace them with original art.

tsc's People

Contributors

aakburns avatar amdmi3 avatar balintkissdev avatar brianvanderburg2 avatar darkacez avatar datahead8888 avatar default0 avatar devnexen avatar fluxy avatar georgeraraujo avatar giby avatar hgdagon avatar jpenguin avatar kirbyfan64 avatar kolewu avatar lambda-11235 avatar luiji avatar polluks avatar quintus avatar refi64 avatar rezso avatar smcameron avatar sonofbowser avatar susnux avatar tobbi avatar tristanheaven avatar urbalazs avatar xet7 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

tsc's Issues

Integrate video detail and audio settings into preferences

This code in preferences.cpp:

    // FIXME: Merge these settings with the other ordinary settings
    // in a cPreferences instance! The following lines set global
    // variables, which from the outside is totally unexpected.
    // This must be done in main.cpp instead, where the preferences
    // are loaded!
    pVideo->m_geometry_quality = loader.Get_Video_Geometry_Detail();
    pVideo->m_texture_quality  = loader.Get_Video_Texture_Detail();
    pAudio->m_music_volume     = loader.Get_Audio_Music_Volume();
    pAudio->m_sound_volume     = loader.Get_Audio_Sound_Volume();

sets global variables where it is totally unexpected from the outside. The 4 relevant settings must be included into cPreferences and the corresponding globals must be set in the calling context in main.cpp on game startup.

Eliminate incomplete constructors

At some parts SMC classes have constructors that do not actually build a complete object. Instead, they rely on the calling code to actually complete the object. Take for example the constructor of cOverworld:

cOverworld :: cOverworld( void )
{
    m_sprite_manager = new cWorld_Sprite_Manager( this );
    m_animation_manager = new cAnimation_Manager();
    m_description = new cOverworld_description();
    m_layer = new cLayer( this );

    // ...

    m_next_level = 0;

    m_player_start_waypoint = 0;
    m_player_moving_state = STA_STAY;
}

This code is incomplete. Why? It constructs an instance of cOverworld_description and does not initialize it. Why does this matter? Because cOverworld_description’s constructors does something entirely undocumented:

cOverworld_description :: cOverworld_description( void )
{
    m_path = "world_1";
    m_name = _("Unnamed");
    m_visible = 1;
    m_user = 0;

    m_comment = _("Empty");
}

It defaults to loading the world world_1! The consequence of this is that if you create an instance of cOverworld, you are forced to post-initialize it by manually changing the chosen overworld afterwards, but before you call any method on your new object. Check out what cOverworld_Manager::Load_Dir() does:

                // ...
                overworld = new cOverworld();

                // set directory path
                overworld->m_description->m_path = fs::path(current_dir);
                // default name is the path
                overworld->m_description->m_name = path_to_utf8(current_dir.filename());
                // set user
                overworld->m_description->m_user = user_dir;

                objects.push_back( overworld );

                overworld->Load();
            }

Do you see how this first constructs the new cOverworld instance, then post-initializes its m_description member, and then calls the Load() method on the object? This is very bad code quality as it violates one of the main principles of object-oriented programming, the principle of secrecy. As the caller, I do not need to bother on how to create an object, I do not need to cater for an objects internals. I call it’s class’ constructor (potentially with arguments), and have a ready-to-use object.

This code needs to be wiped out entirely and replaced with proper constructors that take arguments to build the instances the way they need to be built.

Valete.

Use a proper XML library instead of CEGUI’s XML lib

People are constantly having problems with their CEGUI not having the NullRenderer and using a proper XML library directly rather than CEGUI’s (not really good) wrapper is better anyway. Use libxml++ instead.

The following things need to be done in order to remove CEGUI’s XML handling:

  • Convert the level loader to libxml++✓
  • Convert the world loader to libxml++ ✓
  • Convert the savegame loader to libxml++ ✓
  • Convert the user preferences loader to libxml++ ✓
  • Convert the editor config loader to libxml++ ✓
  • Convert the campaign loader to libxml++ ✓
  • Convert the level writer to libxml++ ✓
  • Convert the world writer to libxml++ ✓
  • Convert the savegame writer to libxml++ ✓
  • Convert the user preferences writer to libxml++ ✓
  • Convert the campaign writer to libxml++ ✓

Different Flyon colors not shown in editor

Since a long time, there is a blue Flyon in SMC that is available for levels, but nobody knows about it, since it is not displayed in the "enemy" menu of the editor. I also observed the same behaviour for the newly-added mecha flyon. Not sure what causes this, though.

Merge cSave and cSavegame

The cSavegame and cSave classes are effectively doing two parts of the same job. They should be merged into one single class cSave or so.

Ghost maryo issue

See http://secretmaryo.org/phpBB3/viewtopic.php?f=22&t=7821 , patch by deved2:

*** savegame.cpp    2012-03-24 06:31:02.000000000 -0400
--- savegame_new.cpp    2012-04-25 07:25:39.000000000 -0400
*************** void cSave :: Init( void )
*** 177,182 ****
--- 177,186 ----
    m_player_type = 0;
    m_player_state = 0;
    m_itembox_item = 0;
+   if( m_maryo_type == MARYO_GHOST )
+   {
+       m_player_previous_state = 0;
+   }

    // level
    m_level_time = 0;
*************** bool cSavegame :: Save_Game( unsigned in
*** 493,498 ****
--- 497,506 ----
    savegame->m_lives = pLevel_Player->m_lives;
    savegame->m_points = pLevel_Player->m_points;
    savegame->m_player_type = pLevel_Player->m_maryo_type;
+   if( m_maryo_type == MARYO_GHOST )
+   {
+       savegame->m_player_previous_type = pLevel_Player->m_maryo_type_temp_power;
+   }
    savegame->m_player_state = pLevel_Player->m_state;
    savegame->m_itembox_item = pHud_Itembox->m_item_id;

Convert all the paths to boost::filesystem

SMC has handled all paths as std::string instances until now. I’ve largely rewritten the resource management system to use boost::filesystem instead (and made pResource_Manager a real resource manager), but enough artifacts remain to have the game crash at start.

Depends on #3.

Replace m_type with pure C++ type information?

Currently, each sprite has a member named m_type that denotes what type of sprite it is, e.g. TYPE_FURBALL or TYPE_PARTICLE_EMITTER. In other words, this duplicates the information already present in the C++ type system itself. For example, a check like this:

if (p_sprite->m_type == TYPE_FURBALL)
  // Do things

can be replaced with the following equal code that relies on C++’s type system instead (yes, all furballs have m_type set to TYPE_FURBALL in their constructor):

if (dynamic_cast<cFurball>(p_sprite))
  // Do things

This also has the advantage we can check for intermediate classes like cEnemy instead of having to list all enemy types existing in SMC.

However, I’m not sure where these m_type checks are done in SMC’s code. dynamic_cast is AFAIK a more expensive operation, i.e. it doesn’t perform as good as a simple integer check does (m_type is of type SpriteType, which is an enum, which is an integer). If such checks happen somewhere in SMC’s Update() or Draw() functions, they are called on every (!) frame, which would make a switch to dynamic_cast probably impossible. This needs to be checked; however, if there aren’t such highly frequented checks, we should probably remove SpriteType entirely and completely rely on C++’s type system.

Valete,
Quintus

Replace "type" in settings file with "massivity" or so

Currently, the image settings files accept a parameter called type that defines the massivity of the image. This is misnamed and should hint at what it does by being named massivity or so -- I’m not a native english speaker, please make suggestions.

Depends on #42.

Valete,
Quintus

Remove direct attribute access and replace with proper getter methods

The SMC code contains much code like this (taken from savegame.cpp):

Add_Property(p_node, "level_name", p_level->m_name)

The p_level->m_name thing should go; direct external access to member variables is C-ish struct style, but not proper OOP. There should be getter methods defined instead, so that the code reads:

Add_Property(p_node, "level_name", p_level->Get_Name())

Virtual File System

When I get time and we've dealt with our other problems, I would like to write a small C++ library similar to PhysicsFS [1] that would provide a simple virtual file system. The advantage of this would be the ability to prevent file name collision. For instance, Package A might add an image called cherry.png, and Package B might provide the same image. The virtual file system only mounts relevant data to a given level, so a level in Package A would just mount Package A and the core file set.

Additionally, if we ever add new images to the core file set, we don't have to worry about the packages overwriting them, since they just override them in the virtual file system. If the maintainer of one of the packages wants access to that, than they can voluntarily, and without much trouble, edit their own file name so they can see the file they override. If they have no want to access that overridden image, they have no need to update the package.

This would function just well with resource packs. I like the idea that people can create resource packages that level editors can add without the mainline having to add them manually. With this mechanism, resource pack collisions wouldn't be nearly as much of an issue, and different level packs could use different versions of the same resource pack without any collision problems.

One of the features I want to add to the C++ library is the ability to support transparent reads from archives (the same as C++), so that we can change the package format we designed with SMC-GET to simple ZIP files (required instead of tarballs for better random access) or 7Z files that people can easily create and just drop into SMC without having to extract anything. It would also help save disk space by compressing the level and script files.

The reason I would like to write a custom C++ library instead of using PhysicsFS is for ease of integration into SMC. I'd write it as an external system that we could include similarly to mruby so it wouldn't much count as an external library. Plus, I've been interested in writing my own virtual file system library for awhile. ;)

[1] http://icculus.org/physfs/

Make collision handlers protected

The collision handlers (Handle_Collision_Player(), Handle_Collision_Enemy(), etc.) are currently public methods. They are not intended to be called from the outside of a sprite, but they do have an inheritance chain (they’re virtual), so they should be protected.

Valete,
Quintus

Remove code duplication in enemies

I just noticed that each and every single enemy contains this code (this one taken from the furball):

void cFurball :: Update( void )
{
  // ...
  if( !m_valid_update || !Is_In_Range() )
  {
    return;
  }

  // ...
}

This checks whether an update shall be executed on the sprite as per internal conditions of the sprite (m_valid_update) and as per the current camera update range (Is_In_Range()). That code is the very same for nearly all the sprites, and should just be moved way up in the inheritance hierarchy.

Generally, I have the feeling that especially the enemies contain a lot of duplicated code that should just be moved to cEnemy. I have to re-check this, tough.

Valete,
Quintus

Don’t scroll credits infinitely

Currently, the credits scroll infinitely, again and again (and with graphic errors towards the "special thanks"). The credits should exit to the main game menu when done, there’s no real reason why they should keep repeating over and over.

Vale,
Quintus

Entering a Pipe While Invincible

Entering a pipe will stop the invincibility but the music will continue to play until it reaches the end of the song (which is far longer than the star lasts).
The pipe won't stop the invincibility if it leads to another area in the same level, but if the pipe goes to another level, the glitch will occur.

Move m_level_ends_if_killed to cEnemy

The m_level_ends_if_killed member currently only exists for specific enemies, namely the furball boss and the turtle boss. While for normal gameplay this is fine, for scripting it would be much more interesting to have the level end when any given enemy is killed, e.g. a spika or so. This requires the m_level_ends_if_killed member to be moved directly into the cEnemy class and merging the slightly different code currently in use in the cFurball and cTurtleBoss classes into one common place.

Vale,
Quintus

Small Krush in editor

Krushes should have an option to be set to small. That is, you double-click on the Krush, and next to the direction box there should be an option to make it small.

Lava

This has so often been requested, one should really add that to SMC.

Valete,
Quintus

Convert calls to XmlAttributes::fetch() to templated variant

Before today XmlAttributes::fetch() wasn’t templated, but only worked with strings, requiring an absolutely unnecessry conversion of the defaultvalue to a string before it could be converted back. Example:

Old:

// audio/random_sound.cpp
Set_Volume_Reduction_Begin(string_to_float(attributes.fetch("volume_reduction_begin", float_to_string(m_volume_reduction_begin))));

New:

// audio/random_sound.cpp
Set_Volume_Reduction_Begin(attributes.fetch<float>("volume_reduction_begin", m_volume_reduction_begin));

This has been changed for many sprites, but especially the enemies have not been changed yet. You’ll always find these calls in the constructors of cSprite subclasses whith this signature (yes cRandom_Sound is a subclass of cSprite):

// audio/random_sound.h
cRandom_Sound( XmlAttributes &attributes, cSprite_Manager *sprite_manager );

As this is not only nicer to read, but also improves loading performance (the conversion of the defaultvalue is missing), this should be changed soon.

Vale,
Quintus

Remove TYPE_MASSIVE, etc. from SpriteType enum

The SpriteType enum is mainly used for determining the "class" of an object without having to look at it’s C++ class information (mainly for performance reasons I guess). It however appears to be cluttered with the massivity information:

    TYPE_PASSIVE = 44,
    TYPE_FRONT_PASSIVE = 45,
    TYPE_MASSIVE = 46,
    TYPE_HALFMASSIVE = 5,
    TYPE_CLIMBABLE = 47,

which is redundant with the MassiveType enum further below in game_core.hpp:

enum MassiveType
{
    MASS_PASSIVE = 0,
    MASS_MASSIVE = 1,
    MASS_HALFMASSIVE = 2,
    MASS_CLIMBABLE = 3
};

The massivity information should be removed from the SpriteType enum and SMC should completely rely on the MassiveType enum and it’s corresponding m_massive_type member of cSprite.

Valete,
Quintus

Remove all instances of DATA_PATH from the sources and use pResource_Manager instead.

The compiled-in fixed resource path is now history. Instead, the resource manager determines the current executable’s path and retrieves the data directory from there (unless you use the FIXED_DATA_PATH compilation option to force a specific directory). However, there are still far too many references to DATA_PATH (whose definition I’ve already removed) in the sourcecode which must go.

Replace game data XML (!) with hashmap

SMC currently stores it’s game state as in-memory XML. WTF?

// Game Action data
extern CEGUI::XMLAttributes Game_Action_Data_Start;
extern CEGUI::XMLAttributes Game_Action_Data_Middle;
extern CEGUI::XMLAttributes Game_Action_Data_End;

This is never written out to disk, hence there is absolutely no need to use XML for this. These variables should all be replaced with something based on std::map. Maybe extract the type-conversion code from SMC’s own XmlAttributes and work with subclasses? Or just rename it to something more generic?

Transition from centralized XML loading to decentralized

Currently, there’s a huge function Create_Level_Object_From_XML() in level.cpp that contains a giant if clause checking for every possible object in the XML level file. As it appears, there’s also an unknown amount of decentralised virtual Load_From_XML() methods that are never used. These need to be synchronised with the centralised loading code, which should then be kicked out in favour of the decentralised system which allows for a much more easy addition/removal of new/old elements.

This should probably solved together with #9.

Use std::cerr for printing warnings

Warnings should go to standard error, not to standard output. SMC often uses printf(), which a) prints to standard output and b) is legacy C code if you don’t need to formatting functionality (in which case fprintf() should be used with the standard error stream here).

Loose shells

Shells that are just lying around, without army inside. Maryo can pick them up, let them roll, stop them, but there’s no enemy in them. Just an empty shell.

Add a proper exception system to TSC

Currently, SMC has no concept of exception handling. It prints wealths of warnings, whose conditions may even crash the game later on and which make debugging unneccessarily hard because you have to manually determine where the warning came from rather than just having GDB figure out where an exception popped up from. A proper exception system should use proper exception classes which useful error messages and a good exception hierarchy.

Windows installer

I’ve heard that on Windows, you don’t have a package manager. Really poor guys. So we need to provide them with an installer; CMake has native support for building these, called CPack.

Valete,
Quintus

Support CEGUI 0.8.x

Currently, SMC only officially supports CEGUI 0.7.x. It’s time to move on!

  • Depends on #9

Loading Level with Timer Causes Game to Crash

Steps to reproduce:
Load a level that has a script + timer. Press Esc, and try to start another level (can even be the same one with the script). If it does not crash here, just Esc and pick one again. It should happen this time.
The error it spawns is:

terminate called after throwing an instance of 'boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<boost::lock_error> >'
  what():  boost: mutex lock failed in pthread_mutex_lock: Invalid argument
Aborted

Seems like someone forgot to stop timers when exiting a level...

Kid-friendly File Selector

We need a file selector that's much easier for people who are not quite familiar with computer mechanics, as opposed to the filename/here "selector".

Missing scripting features

A (possibilty incomplete) list of what should be implemented on the scripting side:

  • Quick’n’easy way to create a static sprite ✓
  • mruby classes for all existing enemies ✓
  • mruby classes for all existing powerups ✓
  • mruby classes for all existing boxes✓
  • Helper classes for common static sprites (like door + levelexit)
  • Scripting paths for moving/falling platforms ✓
  • Scripting timers ✓
  • Level save and load events ✓
  • The infamous touch event ✓
  • Allow scripts to hijack Maryo’s movements
  • Allow scripts to apply powerups directly to Maryo ✓
  • Allow scripts to display messages ✓

Feel free to add to this issue what you would like to see in scripting.

Valete.

Split powerup classes into separate files

Currently, powerup.cpp and powerup.h contain multiple classes. This is bad style; there should be a directory powerups/ that contains separate files for cMushroom, cFirePlant, etc.

Saving in the Overworld Crashes Game

Steps to reproduce:
Select any world, press Esc, go to "Save", save the game, press Esc, try to enter either the Load menu or Save menu and the game will crash.
This happens because SMC displays the level's current time in the Save/Load menus, but since the overworld does not have time, it can't find a time to display.

Add Pip enemy

Pip, the worm! See this forum thread for ideas.

  • It is a two-hit enemy.
  • On first hit, it splits into two small pips.
  • On second hit, it dies and gives Maryo a large Y acceleration (must be greater than the power jump)
  • Can only be defeated by non-small Maryo

Multiple level exits for overworld

Currently only one path is possible on the overworld. We should have the possibility to unravel paths depending on which level exit the user took in a level.

Better overworld path handling

The path handling in overworlds currently is confusing and hard to predict. Instead of working with lines which may or may not work we should have some definite list which waypoint can unlock which other waypoints. The necessary directions the player must go can most likely be determined by looking at the positions of unlocked waypoints.

Or in short, rewrite the entire path handling code for overworlds.

Split cFurball in multiple classes

Currently the cFurball class covers the normal brown, icy blue and giant boss furball. These furballs however do not only have different colors and sizes, they behave differently and should be separate classes that inheritc from a common cFurball class. Code like

if (m_type == TYPE_FURBALL_BOSS) {
  // ...
}

must vanish, this is not OOP.

Vale,
Quintus

Replace all fs declarations with one in global_game.h

In nearly every .cpp source file of SMC there is a line like this:

namespace fs = boost::filesystem;

This is annoying. They should all be removed and replaced with one single line in global_game.h, that is thereby included into all sourcefiles.

Vale,
Quintus

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.