Les membres ayant 30 points peuvent parler sur les canaux annonces, projets et hs du chat.
La shoutbox n'est pas chargée par défaut pour des raisons de performances. Cliquez pour charger.
Menu
Calculatrices
Graph 35 à 100
Graph 25+Pro/25+E/25+E II
Graph 35+USB/75(+E)/85/95 SD
Graph 100(+)
Classpad 300/330(+)
fx-CG 10/20 (Prizm)
Classpad 400(+E)
Graph 90+E
fx-92+ SC
Liens
¤ Vous cherchez une fonction ?
Jeux >> Graph 90+E >> Add-ins >> Super Mario 3D
Super Mario 3D
Version : 1.0 Taille : 655000 octets Ajouté le : 2023-04-24 05:54 Modifié le : 2023-04-26 03:26
Auteur et posteur :
FarhiHors ligneMembrePoints: 1380 Défis: 0 Message
Planète Casio - Add-in Casio - Super Mario 3D - farhi - Calculatrices
Nombre de visites sur cette page : 6466
Score au progrank : 74
Note actuelle : 8.5/10 noté 6 fois
Vous devez être connecté(e) pour noter (inscription).
8473 téléchargements | Voir les Tests (3)

Ce programme est sous licence Creative Commons 2.0 BY-NC


Description :

Ma participation à la Chill Casio Jam #2.

Bon, est-ce que j'ai vraiment besoin d'expliquer ce qu'est un jeu Mario ?

Mis à part cela, ce jeu est en 3D (oui, oui, en 3D sur Casio). Toutes les commandes sont expliquées dans le jeu. Cependant, ce qui n'est pas précisé, c'est qu'il est possible de quitter le jeu à tout moment en appuyant sur le bouton MENU.

Pour le moment, il n'y a qu'un seul niveau (qui m'a pris énormément de temps à créer, donc je n'ai pas eu le temps d'en faire un autre). Mais au moins, ce niveau montre une grande variété de possibilités. Je n'ai pas eu le temps de terminer les Goombas et autres ennemis divers, mais ils seront disponibles lors d'une prochaine mise à jour.

Cependant, si certains d'entre vous sont intéressés pour m'aider à créer d'autres niveaux, faites-le moi savoir. La démo ne le montre pas, mais il est possible de faire beaucoup plus de choses avec ce moteur 3D (on peut étendre la profondeur bien plus qu'à 4 blocks par exemple).

Félicitations à celui qui a réussi à récupérer les 10 pièces !

La vidéo ci-dessous a été enregistrée avec la version Windows (c'est pourquoi elle est plus fluide que sur la Casio).
Bon divertissement !


Note sur 10 Commentaire Date de notation
8Exploite la graph 90+E à son maximum. J'apprécie beaucoup l'inspiration de Super Mario 3D Land qui lui aussi adapte le LD des niveaux en 2D dans un espace 3D. Dommage que les ombres n'aient pLe 01.05.2023 à 00:01
8.5Voir le testLe 08.11.2023 à 14:12
9Voir le testLe 24.04.2023 à 10:02
9Quelques bugs graphiques mais très impressionant techniquement !Le 24.04.2023 à 10:03
8.5Voir le testLe 28.04.2023 à 22:04
8Techniquement fort un mode 3D nouveau, je suis curieux de voir comment le format peut être exploité. - Lephe'Le 30.04.2023 à 23:12

Commentaires :

Pages: Précédente | 1, 2, 3, 4, 5 | Suivante

FarhiHors ligneMembrePoints: 1380 Défis: 0 Message
Posté le 25-04-2023 à 23:43 | #
Dimartino a écrit :
D'après ce que j'ai vu sur la vidéo ça a l'air d'être du travail de fou !

Merci

Vous avez quoi comme casio ?
FarhiHors ligneMembrePoints: 1380 Défis: 0 Message
Posté le 26-04-2023 à 03:30 | #
Mise à jour (attendez vous à en avoir encore d'autres)
Ajout d'un menu principal et menu de sélection de niveaux (même si pour l'instant il n'y en a toujours qu'un seul)
Le menu principal utilise le moteur graphique, ce n'est pas une image fix si vous vous posez la question
SlyvttEn ligneMaître du PuzzlePoints: 2410 Défis: 17 Message
Posté le 28-04-2023 à 22:07 | #
Testé pour ma part, c'est top, fais nous des niveaux en plus STP !!!!! Encore des niveaux (et des ennemis / powerups).

Bravo Farhi
FarhiHors ligneMembrePoints: 1380 Défis: 0 Message
Posté le 28-04-2023 à 22:25 | #
Merci
J'en ferai d'autres mais pour le moment je suis un peu pris.
A la limite je peut essayer de mettre à disposition à éditeur au pire. Un Super Mario Maker 3D . Mais après on aura pas toute la flexibilité qu'avec le code de base.
Faire les niveaux c'est pas compliqué mais c'est très long.
Par exemple le niveau 1 a cette tête là :

void Level_1(){
    CreateWorld(101,90, 25, 4);
    //world->background = PC_LoadTexture("assets/Images/Backgrounds/sky_bg.jpg");
    if (MainCamera != NULL)
        Camera_delete(MainCamera);
    MainCamera = Camera_new(0,250,0);
    MainCamera->angle = -100;

    Player* p = CreatePlayer(AllSprites[Sprite_Player], 2*BLOCK_SIZE, 4*BLOCK_SIZE, 1*BLOCK_SIZE);
    //Player* p = CreatePlayer(CreateSprite(AllTextures[0], (PC_Rect){BLOCK_SIZE, 0, BLOCK_SIZE, BLOCK_SIZE}), 2, 3, 1);
    PlaceEntity(p->entity, 2, 4, 1);
    world->player = p;
    world->DrawWorldUI = DrawWorldUI;

    //Entities Control
    //PlaceEntity(CreateEntity(AllSprites[Sprite_Entities+11], 2, 4, 1), 4, 5, 1);//SHIFT
    //PlaceEntity(CreateEntity(AllSprites[Sprite_Entities+12], 2, 4, 1), 6, 4, 1);//ALPHA
    //PlaceEntity(CreateEntity(AllSprites[Sprite_Entities+13], 2, 4, 1), 8, 5, 1);//F1
    //PlaceEntity(CreateEntity(AllSprites[Sprite_Entities+14], 2, 4, 1), 9, 4, 1);//F2

    //Entities coins
    //SpawnCoin(4,3,1);

    //Entities Items
    //SpawnHeart(5,3,1);

    /////////////////////////////////////
    /////////////////////////////////////
    //Level Blocks
    for (size_t x = 0; x < 23; x++)
        for (size_t z = 0; z < 4; z++)
            PlaceBlock(CreateBlock(GRASS, 0, 0, 0), x, 2, z);

    for (size_t x = 0; x < 23; x++)
        for (size_t y = 0; y < 2; y++)
            PlaceBlock(CreateBlock(DIRT, 0, 0, 0), x, y, 0);
    for (size_t z = 0; z < 4; z++)
        for (size_t y = 0; y < 2; y++)
            PlaceBlock(CreateBlock(DIRT, 0, 0, 0), 22, y, z);

    //SpawnMysteryBox( 0, 5, 0);
    //SpawnBrickBreakable( 2, 5, 0);

    //Entites PNJ
    DialoguePack* pack = NewDialoguePack(NewDialogue(Dialogues,"Panneau",0,NULL,NULL,(lambdaFunction){Background_DrawWorld, NULL}));
    SpawnPNJ(AllSprites[Sprite_Entities+5], 3, 3, 2, pack);
    //Entities Control
    PlaceEntity(CreateEntity(AllSprites[Sprite_Entities+10], 2, 4, 1), 3, 5, 3);//cross

    for (size_t x = 7; x < 9; x++)
        for (size_t z = 0; z < 3; z++)
            for (size_t y = 3; y < 8; y++)
                PlaceBlock(CreateBlock(DIRT, 0, 0, 0), x, y, z);

    for (size_t x = 11; x < 13; x++)
        for (size_t z = 1; z < 4; z++)
            for (size_t y = 3; y < 8; y++)
                PlaceBlock(CreateBlock(DIRT, 0, 0, 0), x, y, z);
    
    //Entites PNJ
    pack = NewDialoguePack(NewDialogue(Dialogues+4,"Panneau",0,NULL,NULL,(lambdaFunction){Background_DrawWorld, NULL}));
    SpawnPNJ(AllSprites[Sprite_Entities+5], 16, 3, 2, pack);

    SpawnCoin(19,3,1);

    pack = NewDialoguePack(NewDialogue(Dialogues+8,"Panneau",0,NULL,NULL,(lambdaFunction){Background_DrawWorld, NULL}));
    SpawnPNJ(AllSprites[Sprite_Entities+5], 21, 3, 2, pack);

    PlaceEntity(CreateEntity(AllSprites[Sprite_Entities+11], 23, 5, 1), 23, 5, 3);//SHIFT

    for (size_t x = 26; x < 28; x++)
        for (size_t z = 1; z < 3; z++)
            for (size_t y = 1; y < 2; y++)
                PlaceBlock(CreateBlock(DIRT, 0, 0, 0), x, y, z);

    for (size_t x = 26; x < 28; x++)
        for (size_t z = 1; z < 3; z++)
            PlaceBlock(CreateBlock(GRASS, 0, 0, 0), x, 2, z);

    for (size_t x = 23; x < 30; x++)
        for (size_t z = 0; z < 4; z++)
            PlaceBlock(CreateBlock(LAVA, 0, 0, 0), x, 0, z);

    SpawnCoin(27,3,1)->x-=BLOCK_SIZE/2;


    ///P2
    for (size_t x = 30; x < 52; x++)
        for (size_t z = 0; z < 4; z++)
            PlaceBlock(CreateBlock(GRASS, 0, 0, 0), x, 2, z);

    for (size_t x = 30; x < 52; x++)
        for (size_t y = 0; y < 2; y++)
            PlaceBlock(CreateBlock(DIRT, 0, 0, 0), x, y, 0);
    for (size_t z = 0; z < 4; z++)
        for (size_t y = 0; y < 2; y++)
            PlaceBlock(CreateBlock(DIRT, 0, 0, 0), 51, y, z);
    for (size_t z = 0; z < 4; z++)
        for (size_t y = 0; y < 2; y++)
            PlaceBlock(CreateBlock(DIRT, 0, 0, 0), 30, y, z);

    //SpawnGoomba(32, 3, 2);

    pack = NewDialoguePack(NewDialogue(Dialogues+4*3,"Panneau",0,NULL,NULL,(lambdaFunction){Background_DrawWorld, NULL}));
    SpawnPNJ(AllSprites[Sprite_Entities+5], 33, 3, 2, pack);

    PlaceEntity(CreateEntity(AllSprites[Sprite_Entities+13], 2, 4, 1), 34, 5, 0);//F1
    PlaceEntity(CreateEntity(AllSprites[Sprite_Entities+14], 2, 4, 1), 36, 5, 0);//F2

    for (size_t z = 0; z < 4; z++)
        for (size_t x = 37; x < 43; x++)
        {
            if ((x==38 ||x==39||x==40)&& (z==4 || z==3 || z==2))
                continue;
            PlaceBlock(CreateBlock(BRICK, 0, 0, 0), x, 6, z);
            PlaceBlock(CreateBlock(BRICK, 0, 0, 0), x, 7, z);
        }

    SpawnKey(39, 6, 3)->y-=BLOCK_SIZE/2;

    pack = NewDialoguePack(NewDialogue(Dialogues+4*4,"Panneau",0,NULL,NULL,(lambdaFunction){Background_DrawWorld, NULL}));
    SpawnPNJ(AllSprites[Sprite_Entities+5], 45, 3, 2, pack);

    SpawnCheckpoint(48, 3, 2);

    
    for (size_t x = 52; x < 66; x++)
        for (size_t z = 0; z < 4; z++)
            PlaceBlock(CreateBlock(LAVA, 0, 0, 0), x, 0, z);

    //////
    for (size_t x = 54; x < 56; x++)
        for (size_t z = 3; z < 4; z++)
        {
            for (size_t y = 1; y < 2; y++)
                PlaceBlock(CreateBlock(DIRT, 0, 0, 0), x, y, z);
            PlaceBlock(CreateBlock(GRASS, 0, 0, 0), x, 2, z);
        }

    SpawnCoin(55,3,3)->x-=BLOCK_SIZE/2;

    for (size_t x = 58; x < 60; x++)
        for (size_t z = 3; z < 4; z++)
        {
            for (size_t y = 1; y < 2; y++)
                PlaceBlock(CreateBlock(DIRT, 0, 0, 0), x, y, z);
            PlaceBlock(CreateBlock(GRASS, 0, 0, 0), x, 2, z);
        }

    SpawnCoin(59,3,3)->x-=BLOCK_SIZE/2;

    for (size_t x = 58; x < 60; x++)
        for (size_t z = 0; z < 1; z++)
        {
            for (size_t y = 1; y < 2; y++)
                PlaceBlock(CreateBlock(DIRT, 0, 0, 0), x, y, z);
            PlaceBlock(CreateBlock(GRASS, 0, 0, 0), x, 2, z);
        }

    SpawnCoin(59,3,0)->x-=BLOCK_SIZE/2;

    for (size_t x = 62; x < 64; x++)
        for (size_t z = 0; z < 1; z++)
        {
            for (size_t y = 1; y < 2; y++)
                PlaceBlock(CreateBlock(DIRT, 0, 0, 0), x, y, z);
            PlaceBlock(CreateBlock(GRASS, 0, 0, 0), x, 2, z);
        }

    SpawnCoin(63,3,0)->x-=BLOCK_SIZE/2;
    //////
    ///P2
    for (size_t x = 66; x < 90; x++)
        for (size_t z = 0; z < 4; z++)
            PlaceBlock(CreateBlock(GRASS, 0, 0, 0), x, 2, z);

    for (size_t x = 66; x < 90; x++)
        for (size_t y = 0; y < 2; y++)
            PlaceBlock(CreateBlock(DIRT, 0, 0, 0), x, y, 0);
    for (size_t z = 0; z < 4; z++)
        for (size_t y = 0; y < 2; y++)
            PlaceBlock(CreateBlock(DIRT, 0, 0, 0), 89, y, z);
    for (size_t z = 0; z < 4; z++)
        for (size_t y = 0; y < 2; y++)
            PlaceBlock(CreateBlock(DIRT, 0, 0, 0), 66, y, z);

    pack = NewDialoguePack(NewDialogue(Dialogues+4*5,"Panneau",0,NULL,NULL,(lambdaFunction){Background_DrawWorld, NULL}));
    SpawnPNJ(AllSprites[Sprite_Entities+5], 67, 3, 2, pack);

    for (size_t x = 72; x < 77; x++)
        for (size_t z = 0; z < 4; z++)
        {
            for (size_t y = 0; y < 6; y++)
                PlaceBlock(CreateBlock(DIRT, 0, 0, 0), x, y, z);
            PlaceBlock(CreateBlock(GRASS, 0, 0, 0), x, 6, z);
        }
    for (size_t i = 0; i < 4; i++)
        {
            for (size_t x = 73+i; x < 78; x++)
                RemoveBlock(x, 6-i, 0);
            PlaceBlock(CreateBlock(GRASS, 0, 0, 0), 73+i, 5-i, 0);
        }

    PlaceBlock(CreateBlock(BRICK, 0, 0, 0), 71, 3, 3);
    PlaceBlock(CreateBlock(BRICK, 0, 0, 0), 70, 3, 3);
    PlaceBlock(CreateBlock(BRICK, 0, 0, 0), 69, 4, 3);
    PlaceBlock(CreateBlock(BRICK, 0, 0, 0), 68, 5, 3);
    PlaceBlock(CreateBlock(BRICK, 0, 0, 0), 68, 6, 2);
    SpawnBrickBreakable(71, 5, 2);
    SpawnBrickBreakable(70, 5, 2);

    for (size_t x = 68; x < 72; x++)
        for (size_t z = 0; z < 2; z++)
            PlaceBlock(CreateBlock(BRICK, 0, 0, 0), x, 6, z);


    //FENCE
    Block* block = CreateBlock(FENCE, 0, 0, 0);
    PlaceBlock(block, 67, 7, 0);
    ShowSideBlock(block,0,0,1,0,0,0,0);
    PlaceBlock(CreateBlock(BARRIER_INVISIBLE, 0, 0, 0), 67, 8, 0);
    PlaceBlock(CreateBlock(BARRIER_INVISIBLE, 0, 0, 0), 67, 9, 0);
    
    block = CreateBlock(FENCE, 0, 0, 0);
    PlaceBlock(block, 68, 7, 0);
    ShowSideBlock(block,1,1,0,0,0,0,0);

    block = CreateBlock(FENCE, 0, 0, 0);
    PlaceBlock(block, 67, 7, 1);
    ShowSideBlock(block,0,0,1,0,0,0,0);
    PlaceBlock(CreateBlock(BARRIER_INVISIBLE, 0, 0, 0), 67, 8, 1);
    PlaceBlock(CreateBlock(BARRIER_INVISIBLE, 0, 0, 0), 67, 9, 1);
    
    block = CreateBlock(FENCE, 0, 0, 0);
    PlaceBlock(block, 68, 7, 1);
    ShowSideBlock(block,0,1,0,0,0,0,0);

    block = CreateBlock(FENCE, 0, 0, 0);
    PlaceBlock(block, 69, 7, 0);
    ShowSideBlock(block,1,0,0,0,0,0,0);

    block = CreateBlock(FENCE, 0, 0, 0);
    PlaceBlock(block, 70, 7, 0);
    ShowSideBlock(block,1,0,0,0,0,0,0);

    block = CreateBlock(FENCE, 0, 0, 0);
    PlaceBlock(block, 71, 7, 0);
    ShowSideBlock(block,1,0,0,0,0,0,0);

    pack = NewDialoguePack(NewDialogue(Dialogues+4*6,"Panneau",0,NULL,NULL,(lambdaFunction){Background_DrawWorld, NULL}));
    SpawnPNJ(AllSprites[Sprite_Entities+5], 85, 3, 2, pack);

    SpawnEndDoor(87, 4, 3,LeveL1_End);

    
    SpawnMysteryBox( 79, 5, 0);
    SpawnBrickBreakable( 80, 5, 0);
    SpawnMysteryBox( 81, 5, 0);
    SpawnBrickBreakable( 82, 5, 0);
    SpawnMysteryBox( 83, 5, 0);
    SpawnCoin( 83, 6, 0);

    

    /////////////////////////////////////
    /////////////////////////////////////
    CullingShadowWorld();
    ResetCameraPosition(p);
    UpdateWorld();    
    FadeOut((lambdaFunction){Background_DrawWorld, NULL});
}


Après si tu veux m'aider à en faire il n'y a pas de soucis @Slyvtt
LephenixnoirEn ligneAdministrateurPoints: 24673 Défis: 170 Message
Posté le 30-04-2023 à 23:10 | #
Fascinante production ! Je crois que c'est le seul jeu que j'ai testé sur cette plateforme qui utilise cette semi-3D. Étonnamment j'ai l'impression que certains bouts du niveau antagonisent la perspective. Typiquement, avec la vue qu'on a on ne perçoit pas tout l'espace hyper bien, et tu mets un escalier pile dans le sens où en voit le moins ; pareil pour la clé. Dans Super Mario 3D World, les niveaux font exprès d'utiliser des constructions/variations 3D qu'on peut comprendre facilement avec une vue de côté. Est-ce délibéré de ne pas faire comme ça ?

Quelques notes :
- EXE c'est casse-pieds à aller chercher tout le temps, quid de ALPHA ou OPTN ?
- Une ombre sous les pièces aiderait vraiment à percevoir où elles sont dans l'espace
- Le mouvement est pas super fluide, peut-être qu'il est possible d'imiter les plateformers 2D classiques qui font ça à la perfection ?
Gky93Hors ligneMembrePoints: 268 Défis: 0 Message
Posté le 01-05-2023 à 00:20 | #
Bon le commentaire de ma note a été coupé du coup je vais le continuer ici.
J'imagine que c'est par choix pour privilégier les perfs mais je trouve dommage que les ombres n'aient pas été plus exploités pour la clé par exemple (sinon le placement et les mouvements de caméra sont parfaits).
FarhiHors ligneMembrePoints: 1380 Défis: 0 Message
Posté le 01-05-2023 à 01:18 | #
Lephenixnoir a écrit :
Étonnamment j'ai l'impression que certains bouts du niveau antagonisent la perspective

Tout à fait ! J'ai fait exprès de cacher certains élément pour forcer le joueur à changer l'angle de la caméra, c'est une démo après tout donc je montre tout ce qu'on peut faire même si ça va à l'encontre de l'aspect facile de Super Mario 3D World/Land.
Mais pour les prochains niveaux je vais essayer de m'y conformer.

Lephenixnoir a écrit :
EXE c'est casse-pieds à aller chercher tout le temps, quid de ALPHA ou OPTN

ALPHA est déjà réservé pour les Power-Up (pas encore utilisable), à la limite OPTN pourquoi pas... Personnellement je vois EXE comme la touche "principale" de la Casio. Dans le pire des cas, je peux faire en sorte qu'il accepte les deux touches.

Lephenixnoir a écrit :
Une ombre sous les pièces aiderait vraiment à percevoir où elles sont dans l'espace

J'ai un contrôle totale sur les entités, je peux en effet dire celles qui auront une ombre. Je prends note.

Lephenixnoir a écrit :
Le mouvement est pas super fluide, peut-être qu'il est possible d'imiter les plateformers 2D classiques qui font ça à la perfection ?

Honnêtement, je penses avoir poussé l'optimisation graphique à son maximum. La seule chose que je peux dire si vous souhaitez avoir plus de FPS, c'est de limiter l'angle de la camera de façon à ce qu'elle soit au ras-du-sol.

Gky93 a écrit :
J'imagine que c'est par choix pour privilégier les perfs mais je trouve dommage que les ombres n'aient pas été plus exploités pour la clé par exemple

Contrairement à ce qu'on pourrait penser, les ombres ne sont pas très couteuses. Les entités sont calculées uniquement quand elles sont dans le champs de caméra. Quand aux blocks, toutes les ombres et les faces sont calculées lors du chargement du monde.
Pour la clé j'ai délibérément choisi de ne pas mettre d'ombre pour forcer le joueur à changer l'angle de la caméra.

Merci à tous pour vos retours, ainsi que pour vos compliments
FarhiHors ligneMembrePoints: 1380 Défis: 0 Message
Posté le 01-05-2023 à 01:26 | #
Ha oui, petit défis : celui qui arrive à traverser un block complet ou qu'il arrive à aller au dessus de la barrière gauche (dans la vidéo à 1min45), je lui fais un niveau dédié.
Pourquoi je dis ça ? Parce que j'ai tellement travaillé sur le système de collision que normalement ce n'est pas possible
LephenixnoirEn ligneAdministrateurPoints: 24673 Défis: 170 Message
Posté le 01-05-2023 à 09:13 | #
Honnêtement, je penses avoir poussé l'optimisation graphique à son maximum. La seule chose que je peux dire si vous souhaitez avoir plus de FPS, c'est de limiter l'angle de la camera de façon à ce qu'elle soit au ras-du-sol.

Je ne parlais pas tant des FPS a priori. Le mouvement "fluide" c'est plutôt l'histoire que y'ait une accélération pas instantanée, un saut plus rapide quand on appuie sur la touche (quitte, si le frame suivant n'arrive pas assez vite, à compenser en simulation), un jump buffer, des trucs comme ça.
FcalvaHors ligneMembrePoints: 603 Défis: 10 Message
Posté le 02-05-2023 à 02:03 | #
Honnêtement, je penses avoir poussé l'optimisation graphique à son maximum.

Je suis quasi sûr qu'en vrai il doit il y avoir encore une tonne d'optimisation possible, en réecrivant les fonctions les plus utilisées en assembleur, ou en faisant des copier coller au lieu de boucles (si si c'est plus rapide) ect.. genre les trucs de l'époque des commodore 64... Et encore si il y a pas plus simple !
Après je dis ça mais je connais que de principe, je serais a peine capable de pointer les endroits a changer, c'est déja incroyable et j'ai hâte de voir ce qui est possible avec le moteur !
Edit : Après avoir vérifié, le "déroulement" de boucles dépend de la machine, donc c'est peu être plus rapide de les minimiser avec la vitesse mémoire limitée de la G90+

Pages: Précédente | 1, 2, 3, 4, 5 | Suivante

Planète Casio v4.3 © créé par Neuronix et Muelsaco 2004 - 2024 | Il y a 103 connectés | Nous contacter | Qui sommes-nous ? | Licences et remerciements

Planète Casio est un site communautaire non affilié à Casio. Toute reproduction de Planète Casio, même partielle, est interdite.
Les programmes et autres publications présentes sur Planète Casio restent la propriété de leurs auteurs et peuvent être soumis à des licences ou copyrights.
CASIO est une marque déposée par CASIO Computer Co., Ltd