Advertisement
Kitomas

(most of the) work for 2024-06-28

Jun 28th, 2024
500
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 15.52 KB | None | 0 0
  1. void handleEdgeWrap(){
  2.   if(!gl_scene.scene)
  3.     throw "gl_scene.scene == 0 (loadScene(>0) before calling handleEdgeWrap()!)";
  4.  
  5.   u16  new_scene_id     = 0;
  6.   bool call_loadObjects = false;
  7.  
  8.  
  9.   if(       gl_player.pos.x < 0        ){ //player went past west side
  10.     gl_player.pos.x  = CANVSIZ_X;
  11.     new_scene_id     = CURRENT_SCENE_PTR->edge_w;
  12.     call_loadObjects = true;
  13.  
  14.   } else if(gl_player.pos.x > CANVSIZ_X){ //player went past east side
  15.     gl_player.pos.x = 0;
  16.     new_scene_id     = CURRENT_SCENE_PTR->edge_e;
  17.     call_loadObjects = true;
  18.  
  19.   }/* else if(gl_player.pos.y < 0        ){ //player went past north side
  20.     gl_player.pos.y  = CANVSIZ_Y;
  21.     new_scene_id     = CURRENT_SCENE_PTR->edge_n;
  22.     call_loadObjects = true;
  23.  
  24.   } else if(gl_player.pos.y > CANVSIZ_Y){ //player went past south side
  25.     gl_player.pos.y  = 0;
  26.     new_scene_id     = CURRENT_SCENE_PTR->edge_s;
  27.     call_loadObjects = true;
  28.  
  29.   }*/ //tbd: uncomment this when i start to use north and south edges
  30.  
  31.  
  32.   if(new_scene_id    ) loadScene(new_scene_id);
  33.   if(call_loadObjects) loadObjects();
  34.  
  35. }
  36.  
  37.  
  38.  
  39.  
  40.  
  41. #define INDICATOR_SPACING 2
  42. static inline void drawAbilityIndicators(){
  43.   shape::rect dst(INDICATOR_SPACING,INDICATOR_SPACING, 10,10);
  44.   shape::rect src(0,0, 10,10);
  45.  
  46.   //shrink
  47.   if(gl_player.has_shrink){
  48.     //src.x = 0;
  49.     gl_spritesheetAbilityIndicators->blitRect(&dst, &src, 0xff00ff);
  50.     dst.x += 10+INDICATOR_SPACING;
  51.   }
  52.  
  53.   //double jump
  54.   if(gl_player.has_dbljmp){
  55.     src.x = 10;
  56.     gl_spritesheetAbilityIndicators->blitRect(&dst, &src, 0xff00ff);
  57.     dst.x += 10+INDICATOR_SPACING;
  58.   }
  59.  
  60.   //speed
  61.   if(gl_player.has_speed){
  62.     src.x = 20;
  63.     gl_spritesheetAbilityIndicators->blitRect(&dst, &src, 0xff00ff);
  64.     //dst.x += 10+INDICATOR_SPACING;
  65.   }
  66.  
  67. }
  68.  
  69. void drawStuff_and_processObjects(){
  70.   bool ro_back = false; //r[ender]o[only] objects that are !in_front
  71.   bool ro_frnt = false; //same thing but only ones with in_front set instead
  72.  
  73.   //I Can't Believe It's Not Assembly!
  74. /*_clear_gray :*/ gl_win->clear(0x808080);
  75.   _draw_bg    :   gl_scene.drawBg();
  76. /*_draw_mg    :*/ gl_scene.drawTiles(false);
  77. /*_proc_obj_bk:*/ if(processObjects(false,ro_back)){ ro_back=true; goto _draw_bg; }
  78. /*_draw_player:*/ gl_player.blit();
  79. /*_draw_fg    :*/ gl_scene.drawTiles(true);
  80. /*_proc_obj_fr:*/ if(processObjects(true ,ro_frnt)){ ro_back=ro_frnt=true; goto _draw_bg; }
  81. /*_draw_ablity:*/ drawAbilityIndicators();
  82.  
  83. }
  84.  
  85.  
  86.  
  87.  
  88.  
  89. //unit should be between 0.0f and 1.0f
  90. color::ARGB unit_to_ryg(f32 unit){
  91.   unit = CLAMP(unit*2, 0.0f, 2.0f);
  92.   u8 red = 255,  green = 255;
  93.  
  94.   #define _RND(_v) (  (u8)( (_v)+0.5f )  )
  95.   if(unit < 1.0f) green = _RND(255.0f*(     unit));
  96.   else            red   = _RND(255.0f*(2.0f-unit));
  97.   #undef _RND
  98.  
  99.   return color::ARGB(red, green, 0, 0);
  100.  
  101. }
  102.  
  103.  
  104.  
  105.  
  106.  
  107. //assumes 8x8 monospaced with 1 pixel of spacing in both x and y
  108. shape::point get_text_size(const char* str){
  109.   if(!str) throw "nullptr string was passed to get_text_size()";
  110.   shape::point result(0,9);
  111.   s32 current_width = 0;
  112.  
  113.   for(; *str != 0; ++str){
  114.     if(*str != '\n'){
  115.       current_width += 9;
  116.     } else {
  117.       result.x  = MAX(result.x, current_width);
  118.       result.y += 9;
  119.       current_width = 0;
  120.     }
  121.   }
  122.  
  123.   result.x = MAX(result.x, current_width);
  124.   if(!result.x) result.y = 0;
  125.  
  126.   return result;
  127.  
  128. }
  129.  
  130.  
  131.  
  132. //x&y determine the CENTER position of the text, not its top-left corner
  133. //calculates text_size if either text_size.x or .y is 0
  134. void drawTextBox(s32 x, s32 y, const char* str, shape::point text_size){
  135.   if(!str) throw "nullptr string was passed to drawTextBox()";
  136.   shape::rect box_rect(x,y, 0,0);
  137.  
  138.   if(!text_size.x || !text_size.y) text_size = get_text_size(str);
  139.  
  140.   box_rect.w  = text_size.x+2;
  141.   box_rect.h  = text_size.y+2;
  142.   box_rect.x -= box_rect.w/2;
  143.   box_rect.y -= box_rect.h/2;
  144.  
  145.   gl_win->drawRectangles(&box_rect, 1, 0x000000);
  146.   gl_win_drawRectEmpty(box_rect, 0x808080);
  147.   gl_text->print(box_rect.x+2, box_rect.y+2, str);
  148.  
  149. }
  150.  
  151.  
  152.  
  153.  
  154.  
  155. #include <object.hpp>
  156. #include <player.hpp>
  157. #include <tile.hpp>
  158.  
  159. using namespace kit;
  160.  
  161. #define GET_OBJ(_type) _type* obj = (_type*)_obj_a
  162. #define GET_DST(_obj_ptr) { _obj_ptr->x, _obj_ptr->y, _obj_ptr->size.x, _obj_ptr->size.y }
  163.  
  164.  
  165. #define OBJIMG(_index) gl_objImg[_index]
  166.  
  167. #define OBJIMG_LEVER_WALL      OBJIMG(1)
  168. #define OBJIMG_ABILITY_SHRINK  OBJIMG(2)
  169. #define OBJIMG_ABILITY_DBLJMP  OBJIMG(3)
  170. #define OBJIMG_ABILITY_SPEED   OBJIMG(4)
  171. #define OBJIMG_ABILITY_REMOVER OBJIMG(5)
  172. #define OBJIMG_SIGNPOST_WOOD   OBJIMG(6)
  173.  
  174. #define TXTLINE(_index) gl_text_lines[_index]
  175.  
  176.  
  177.  
  178.  
  179.  
  180. //copy original state of object data to the active scene
  181. void loadObjects(bool forced, u16 scene_id){
  182.   if(!scene_id && !gl_scene.scene)
  183.     throw "gl_scene.scene == 0 (loadScene(>0) before calling loadObjects()!)";
  184.   if(!scene_id) scene_id = gl_scene.scene;
  185.   if(scene_id > gl_scenes_len) throw "scene_id > gl_scenes_len";
  186.  
  187.   SceneDescriptor* scene_current = gl_scenes[scene_id];
  188.  
  189.   Object* objsCache = gl_objsCache[scene_id];
  190.   Object* objs      = scene_current->objs;
  191.   u16     objs_len  = scene_current->objs_len;
  192.  
  193.  
  194.   if(!forced){ //only copy object data whose persistence flag is false
  195.     for(u32 i=0; i<objs_len; ++i){
  196.       if(!objsCache[i].persistent) objsCache[i] = objs[i];
  197.     }
  198.  
  199.   } else { //otherwise, copy all objects in scene
  200.     for(u32 i=0; i<objs_len; ++i){
  201.       objsCache[i] = objs[i];
  202.     }
  203.  
  204.   }
  205.  
  206. }
  207.  
  208.  
  209.  
  210.  
  211. #define CHECK_TYPE_NULL 0
  212. bool processObjects(bool in_front, bool render_only){
  213.   bool scene_changed = false;
  214.  
  215.   Object* objs      = gl_objsCache[gl_scene.scene];
  216.   u16     objs_len  = gl_scenes[gl_scene.scene]->objs_len;
  217.   Object* obj;
  218.  
  219.  
  220.  
  221.   #if CHECK_TYPE_NULL == 1
  222.     #define TYPE_CHECK  && obj->type != 0
  223.   #else
  224.     #define TYPE_CHECK
  225.   #endif
  226.  
  227.   if(!in_front){
  228.     for(u32 i=0; i<objs_len; ++i){
  229.       obj = &objs[i];
  230.       if(!obj->in_front /*&&*/ TYPE_CHECK)
  231.         scene_changed |= obj->update(obj, render_only);
  232.  
  233.     }
  234.  
  235.  
  236.   } else {
  237.     for(u32 i=0; i<objs_len; ++i){
  238.       obj = &objs[i];
  239.       if(obj->in_front /*&&*/ TYPE_CHECK)
  240.         scene_changed |= obj->update(obj, render_only);
  241.  
  242.     }
  243.  
  244.   }
  245.  
  246.   #undef TYPE_CHECK
  247.  
  248.  
  249.  
  250.   if(!render_only) return scene_changed;
  251.   else             return false;
  252.  
  253. }
  254.  
  255.  
  256.  
  257.  
  258.  
  259. //do not use this object in a scene with more than 2 states
  260. //also, there can in theory be multiple 1lever(s) in a scene,
  261.  //as long as they share the same values of scene_old&new
  262. struct _obj_1lever { //24B; 8x24px sprite
  263.   u16        scene_old; //2B
  264.   u16        scene_new; //2B
  265.   u16           sfx_id; //2B
  266.   //-END OF INIT DATA-
  267.   bool            init; //1B
  268.   bool         flipped; //1B
  269.   Bitmap*          img; //8B
  270.   SoundEffect*     sfx; //8B
  271. };
  272.  
  273. bool obj_1lever(Object* _obj_a, bool render_only){
  274.   GET_OBJ(_obj_1lever); //obj = _obj_a
  275.  
  276.   shape::rect rect_dst = GET_DST(_obj_a);
  277.   shape::rect rect_src(0,0, 8,24);
  278.   bool scene_changed = false;
  279.  
  280.  
  281.   if(!obj->init){
  282.     _obj_a->persistent = 1; //this object is always persistent
  283.  
  284.     obj->init    =  true;
  285.     obj->flipped = false;
  286.     obj->img     = OBJIMG_LEVER_WALL;
  287.  
  288.  
  289.     if(!obj->sfx_id){ //use default sound effect
  290.       obj->sfx = SFXPTR_ACTIVATE_1;
  291.  
  292.     } else if(obj->sfx_id <= gl_sfx_len){ //use specified sound effect
  293.       obj->sfx = SFXPTR(obj->sfx_id);
  294.  
  295.     } else { //no sound effect found
  296.       obj->sfx = nullptr;
  297.       //tbd: warn about nonexistent sound effect
  298.  
  299.     }
  300.  
  301.  
  302.   }
  303.  
  304.  
  305.  
  306.   //if player is touching the object
  307.   if(rects_overlapping(gl_player.getRect(), rect_dst)){
  308.     rect_src.y = 24; //highlighted
  309.     //if player activates the lever
  310.     if(!render_only && CTRLSTATE_GET(down_p)){
  311.       swapScene(obj->scene_old, obj->scene_new);
  312.       obj->flipped ^= 1;
  313.       scene_changed = true;
  314.       SFXPTR_PLAY(obj->sfx);
  315.     }
  316.  
  317.   }
  318.  
  319.   if(obj->flipped) rect_src.x = 8; //lever points down
  320.  
  321.  
  322.   if(obj->img) obj->img->blitRect(&rect_dst, &rect_src, 0xff00ff);
  323.  
  324.   return scene_changed;
  325.  
  326. }
  327.  
  328.  
  329.  
  330.  
  331.  
  332. //0 = shrink
  333. //1 = double jump
  334. //2 = speed
  335. struct _obj_ability { //24B; 24x24px sprite, 24 frames (spritesheet of 24x1)
  336.   u8          which; //1B
  337.   //-END OF INIT DATA-
  338.   bool         init; //1B
  339.   u16  frameCounter; //2B
  340.   u32    _padding32; //4B
  341.   Bitmap*       img; //8B
  342.   bool* has_ability; //8B; ptr to bool that determines if ability is enabled
  343. };
  344.  
  345. bool obj_ability(Object* _obj_a, bool render_only){
  346.   GET_OBJ(_obj_ability); //obj = _obj_a
  347.  
  348.   shape::rect rect_dst = GET_DST(_obj_a);
  349.   shape::rect rect_src(0,0, 24,24);
  350.  
  351.  
  352.   if(!obj->init){
  353.     _obj_a->persistent = 1; //this object is always persistent
  354.  
  355.     obj->init         = true;
  356.     obj->frameCounter = 23; //will roll over to 0 this iteration
  357.  
  358.     //this implementation is quite strange but whatever it works like a charm
  359.     switch(obj->which){
  360.       case 0 : obj->img         = OBJIMG_ABILITY_SHRINK;
  361.                obj->has_ability = &gl_player.has_shrink; break;
  362.  
  363.       case 1 : obj->img         = OBJIMG_ABILITY_DBLJMP;
  364.                obj->has_ability = &gl_player.has_dbljmp; break;
  365.  
  366.       case 2 : obj->img         = OBJIMG_ABILITY_SPEED;
  367.                obj->has_ability = &gl_player.has_speed;  break;
  368.  
  369.       default: obj->img         = gl_tileset_missing;
  370.                obj->has_ability = nullptr;
  371.  
  372.     }
  373.  
  374.   }
  375.  
  376.  
  377.  
  378.   //if player is touching the object (and everything else is valid)
  379.   if(!render_only) //&&
  380.   if(obj->has_ability != nullptr  &&  !(*obj->has_ability)  &&
  381.      rects_overlapping(gl_player.getRect(), rect_dst))
  382.   {
  383.     *obj->has_ability = true;
  384.     SFXPTR_PLAY(SFXPTR_ABILITY_PICKUP);
  385.  
  386.   }
  387.  
  388.  
  389.  
  390.   //pick which frame in the animation to use
  391.   if(obj->has_ability != nullptr){
  392.     //increment animation's frame counter every 13 ticks, which makes for ~9.2fps
  393.     if(!(gl_tickCounter%13)) obj->frameCounter = (obj->frameCounter+1)%24;
  394.  
  395.     rect_src.x = 24 * obj->frameCounter;
  396.     if(*obj->has_ability) rect_src.y = 24; //otherwise it'll remain 0
  397.  
  398.   }
  399.  
  400.  
  401.   //if the has_ability pointer is invalid, disable magenta transparency, since
  402.    //the 'missing tile' bitmap uses the color magenta
  403.   color::ARGB t_color = (obj->has_ability != nullptr) ? 0xff00ff : 0x80000000;
  404.  
  405.   if(obj->img) obj->img->blitRect(&rect_dst, &rect_src, t_color);
  406.  
  407.   return false;
  408.  
  409. }
  410.  
  411.  
  412.  
  413.  
  414.  
  415. //0 = shrink
  416. //1 = double jump
  417. //2 = speed
  418. struct _obj_ability_remover { //24B; 24x24px sprite, spritesheet of 3x1
  419.   u8          which; //1B
  420.   bool    dontReset; //1B; disables resetting player scale back to 2 if .which == 0, etc.
  421.   //-END OF INIT DATA-
  422.   bool         init; //1B
  423.   u8      _padding8; //1B
  424.   u32    _padding32; //4B
  425.   Bitmap*       img; //8B
  426.   bool* has_ability; //8B; ptr to bool that determines if ability is enabled
  427. };
  428.  
  429. bool obj_ability_remover(Object* _obj_a, bool render_only){
  430.   GET_OBJ(_obj_ability_remover); //obj = _obj_a
  431.  
  432.   shape::rect rect_dst = GET_DST(_obj_a);
  433.   shape::rect rect_src(24*obj->which,0, 24,24);
  434.  
  435.  
  436.   if(!obj->init){
  437.     _obj_a->persistent = 1; //this object is always persistent
  438.  
  439.     obj->init = true;
  440.  
  441.     obj->img = OBJIMG_ABILITY_REMOVER;
  442.     if(!obj->img) obj->img = gl_tileset_missing; //this shouldn't happen ever
  443.  
  444.     switch(obj->which){
  445.       case 0 : obj->has_ability = &gl_player.has_shrink; break;
  446.       case 1 : obj->has_ability = &gl_player.has_dbljmp; break;
  447.       case 2 : obj->has_ability = &gl_player.has_speed;  break;
  448.       default: obj->has_ability = nullptr;
  449.  
  450.     }
  451.  
  452.   }
  453.  
  454.  
  455.  
  456.   //if player is touching the object (and everything else is valid)
  457.   if(!render_only) //&&
  458.   if(obj->has_ability != nullptr  &&  (*obj->has_ability)  &&
  459.      rects_overlapping(gl_player.getRect(), rect_dst))
  460.   {
  461.     *obj->has_ability = false;
  462.     SFXPTR_PLAY(SFXPTR_ABILITY_REMOVED);
  463.  
  464.     if(!obj->dontReset)
  465.     switch(obj->which){
  466.       //(case 0 should only fail if i place this object in a subtile-wide space)
  467.       case 0 : gl_player.setScale(2.0f);       break;
  468.     //case 1 : //(not used)
  469.       case 2 : gl_player.enforceMaxVel = true; break;
  470.       default:;
  471.  
  472.     }
  473.  
  474.   }
  475.  
  476.  
  477.  
  478.   //if the has_ability pointer is invalid, disable magenta transparency, since
  479.    //the 'missing tile' bitmap uses the color magenta
  480.   color::ARGB t_color = (obj->has_ability != nullptr) ? 0xff00ff : 0x80000000;
  481.  
  482.   if(obj->img) obj->img->blitRect(&rect_dst, &rect_src, t_color);
  483.  
  484.   return false;
  485.  
  486. }
  487.  
  488.  
  489.  
  490.  
  491.  
  492. //(not specifying w or h results in the default of _obj_a->size.x/y being used!)
  493. struct _obj_generic_sprite { //16B
  494.   u16       which; //2B; objimg index
  495.   u8          w,h; //2B; width and height of source sprite (1B each)
  496.   u8    numFrames; //1B; <2 for no animation (static sprite)
  497.   u8   tick_delay; //1B; 'how many ticks per frame?' (ignored if num_frames < 2)
  498.   //-END OF INIT DATA-
  499.   bool       init; //1B
  500.   u8 frameCounter; //1B
  501.   Bitmap*     img; //8B
  502. };
  503.  
  504. bool obj_generic_sprite(Object* _obj_a, bool render_only){
  505.   GET_OBJ(_obj_generic_sprite); //obj = _obj_a
  506.  
  507.   shape::rect rect_dst = GET_DST(_obj_a);
  508.   shape::rect rect_src(0,0, obj->w,obj->h);
  509.  
  510.  
  511.   if(!obj->init){
  512.     _obj_a->persistent = 1; //this object is always persistent
  513.  
  514.     obj->init         = true;
  515.     obj->frameCounter = obj->numFrames-1; //will roll over to 0 this iteration
  516.  
  517.     if(obj->which <= gl_objImg_len) obj->img = OBJIMG(obj->which);
  518.     if(!obj->img){
  519.       //if i somehow have more than 65k object images,
  520.        //i have bigger problems to worry about
  521.       obj->which = KIT_U16_MAX;
  522.       obj->img   = gl_tileset_missing;
  523.     }
  524.  
  525.  
  526.     //if w/h are 0, then default the src size to the dst size
  527.     if(!obj->w){
  528.       obj->w = (u8)_obj_a->size.x;
  529.       rect_src.w = obj->w;
  530.     }
  531.  
  532.     if(!obj->h){
  533.       obj->h = (u8)_obj_a->size.y;
  534.       rect_src.h = obj->h;
  535.     }
  536.  
  537.   }
  538.  
  539.  
  540.  
  541.   //pick which frame in the animation to use
  542.   if(obj->numFrames > 1){
  543.     //increment animation's frame counter every tick_delay ticks
  544.     if(!(gl_tickCounter%obj->tick_delay))
  545.       obj->frameCounter = (obj->frameCounter+1)%obj->numFrames;
  546.  
  547.     //(which horizontal slot in the spritesheet to use, technically)
  548.     rect_src.x = rect_src.w * obj->frameCounter;
  549.  
  550.   }
  551.  
  552.  
  553.   color::ARGB t_color = (obj->which != KIT_U16_MAX) ? 0xff00ff : 0x80000000;
  554.  
  555.   if(obj->img) obj->img->blitRect(&rect_dst, &rect_src, t_color);
  556.  
  557.  
  558.   return false;
  559.  
  560. }
  561.  
  562.  
  563.  
  564.  
  565.  
  566. struct _obj_msgbox { //24B
  567.   s16      pos_x, pos_y; //4B (2B each)
  568.   u16             which; //2B; gl_text_lines index
  569.   bool      show_always; //1B; always display box, instead of on player collide
  570.   //-END OF INIT DATA-
  571.   bool             init; //1B
  572.   shape::point str_size; //8B
  573.   const char*       str; //8B
  574. };
  575.  
  576. bool obj_msgbox(Object* _obj_a, bool render_only){
  577.   GET_OBJ(_obj_msgbox); //obj = _obj_a
  578.  
  579.   shape::rect rect_collider = GET_DST(_obj_a);
  580.  
  581.   if(!obj->init){
  582.     _obj_a->persistent = 1; //this object is always persistent
  583.  
  584.     obj->init = true;
  585.  
  586.     if(obj->which <= gl_text_lines_len) obj->str = TXTLINE(obj->which);
  587.     if(!obj->str) obj->str = TXTLINE(0); // = "<INVALID TEXT ID>"
  588.  
  589.     obj->str_size = get_text_size(obj->str);
  590.  
  591.   }
  592.  
  593.  
  594.   if(obj->show_always ||
  595.      rects_overlapping(gl_player.getRect(), rect_collider))
  596.   {
  597.     drawTextBox(obj->pos_x, obj->pos_y, obj->str, obj->str_size);
  598.   }
  599.  
  600.  
  601.   return false;
  602.  
  603. }
  604.  
  605.  
  606.  
  607.  
  608.  
  609. #ifndef TEXT_LINES_DEFINITION
  610. extern size_t gl_text_lines_len;
  611. extern const char* gl_text_lines[];
  612.  
  613.  
  614. #else
  615. size_t gl_text_lines_len;
  616. const char* gl_text_lines[] = {
  617. /*0*/ "\
  618. <INVALID TEXT ID>",
  619.  
  620. /*1*/ "\
  621. this is some pretty cool text! :D",
  622.  
  623.  
  624. //(this must be here in order for the length
  625.  //of this array to be properly calculated!)
  626. nullptr,
  627.  
  628. };
  629.  
  630.  
  631. #endif /* TEXT_LINES_DEFINITION */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement