// MapEditor.c - Map Editor #include "global.h" #include "ext.h" // macros for fast tile writing/writing #define PUT_TILE( x, y, tile) TER_SetTile( x, y, -1, tile) // not used #define GET_TILE(x, y) MISC_GetTerrainTileFromCoords(x, y) #define MAPED_MenuItemsCount 6 // command defs #define MAPED_NONE -1 #define MAPED_EXIT 0 #define MAPED_NEW_MAP 1 #define MAPED_LOAD_MAP 2 #define MAPED_SAVE_MAP 3 #define MAPED_SAVE_MAP_AS 4 #define MAPED_SELECT_TILE 5 #define MAPED_SELECT_SPRITE 6 #define MAPED_SELECT_UNIT 7 #define MAPED_CHANGE_DESC 8 #define MAPED_SELECT_POWER 9 #define MAPED_RUN_MAP 10 #define MAPED_AUDIO 11 #define MAPED_PLAYER_START 12 #define MAPED_MESSAGE_TRIGGERS 13 #define MAPED_CHANGE_THEATRE 14 #define MAPED_MINIMAP_MODE 15 #define MAPED_BRUSH_SIZE 16 #define MAPED_AUTHOR 17 #define MAPED_EMAIL 18 #define MAPED_ADVANCED_MAP_TOOLS 19 #define MAPED_TOGGLE_SHOW_UNITS 20 #define MAPED_TOGGLE_PASSABLE_MAP 21 #define MAPED_HELP 22 // macros #define MAPED_wx1 (MAPED_WindowX1 * TILE_X) #define MAPED_wy1 (MAPED_WindowY1 * TILE_Y) #define MAPED_wx2 (MAPED_WindowX2 * TILE_X) #define MAPED_wy2 (MAPED_WindowY2 * TILE_Y) #define MAPED_MouseCellX ((mouse_x - MAPED_wx1)/TILE_X) #define MAPED_MouseCellY ((mouse_y - MAPED_wy1)/TILE_Y) #define MAPED_SpriteInsertX ((MAPED_ox * TILE_X) + mouse_x - (MAPED_WindowX1 * TILE_X)) #define MAPED_SpriteInsertY ((MAPED_oy * TILE_Y) + mouse_y - (MAPED_WindowY1 * TILE_Y)) #define MAPED_SpriteImage DAT_LoadedSprites.sprites[ MAPED_CurrentSprite].frames[ 0].image #define MAPED_UnitImage DAT_LoadedSprites.sprites[ DAT_LoadedRaces.races[ MAPED_CurrentUnit].StillSpriteNumber ].frames[0].image #define MAPED_DrawSpr DAT_LoadedSprites.sprites[ DAT_LoadedRaces.races[ MapUnits[ s].RaceNumber ].StillSpriteNumber ].frames[0].image // map window dimensions in pixels #define MAPED_MapWindowW (MAPED_wx2 - MAPED_wx1) #define MAPED_MapWindowH (MAPED_wy2 - MAPED_wy1) // map window offsets in pixels (including actual map scroll offset) #define MAPED_MapWindowX1 ((MAPED_WindowX1 + MAPED_ox) * TILE_X) #define MAPED_MapWindowY1 ((MAPED_WindowY1 + MAPED_oy) * TILE_Y) #define MAPED_MapWindowX2 (MAPED_MapWindowX1 + MAPED_MapWindowW) #define MAPED_MapWindowY2 (MAPED_MapWindowY1 + MAPED_MapWindowH) // edit modes #define MAPED_EM_TILES 0 #define MAPED_EM_SPRITES 1 #define MAPED_EM_UNITS 2 #define MAPED_EM_POWERUPS 3 #define MAPED_EM_START_ZONES 4 #define MAPED_EM_MESSAGETRIG 5 // water tiles for auto water /* #define WT_TOP_LEFT 10 #define WT_TOP_MIDDLE 7 #define WT_TOP_RIGHT 11 #define WT_LEFT 6 #define WT_MIDDLE 5 #define WT_RIGHT 9 #define WT_BOTTOM_LEFT 13 #define WT_BOTTOM_MIDDLE 8 #define WT_BOTTOM_RIGH 12 */ // start zone colours int StartZoneColours[ SZ_COUNT]; // start zone names char *StartZoneNames[ SZ_COUNT] = { "Single Start Zone", "Coop Start Zone", "H2H 2 Start Zone", "H2H 3 Start Zone", "H2H 4 Start Zone"}; // misc vars char MAPED_EditMode; char MAPED_CurrentFile[ FILENAME_LEN]; int MAPED_CurrentTile, MAPED_CurrentSprite, MAPED_CurrentUnit, MAPED_CurrentPowerUp; int MAPED_WindowX1, MAPED_WindowY1, MAPED_WindowX2, MAPED_WindowY2; int MAPED_ox, MAPED_oy; int MAPED_MousePointer; int MAPED_CurrentMessageString; char MAPED_ModeStr[ 64]; char MAPED_MiniMap; BITMAP *MAPED_PlayerStartBitmap; char MAPED_ShowUnits; BITMAP *TerrainWindow; int MAPED_BorderColour = 0; unsigned char MAPED_BorderColourCtr = 0; char ShowPassableMap; int MAPED_BrushW, MAPED_BrushH; #define MAPED_CL_SPRITE_BORDER CL_YELLOW #define MAPED_CL_UNIT_BORDER CL_GREEN // button defs #define MAPED_BUTTON_NEW 0 #define MAPED_BUTTON_LOAD 1 #define MAPED_BUTTON_SAVE 2 #define MAPED_BUTTON_SAVE_AS 3 #define MAPED_BUTTON_EXIT 4 // seperator #define MAPED_BUTTON_SELECT_TILE 6 #define MAPED_BUTTON_SELECT_SPRITE 7 #define MAPED_BUTTON_SELECT_UNIT 8 #define MAPED_BUTTON_SELECT_POWER 9 #define MAPED_BUTTON_MESSAGE_TRIGGERS 10 #define MAPED_BUTTON_PLAYER_START 11 // sep #define MAPED_BUTTON_BRUSH_SIZE 13 #define MAPED_BUTTON_MINIMAP_MODE 14 #define MAPED_BUTTON_TOGGLE_SHOW_UNITS 15 #define MAPED_BUTTON_TOGGLE_PASSABLE_MAP 16 // seperator #define MAPED_BUTTON_RUN_MAP 18 // seperator #define MAPED_BUTTON_CHANGE_DESC 20 #define MAPED_BUTTON_AUTHOR 21 #define MAPED_BUTTON_EMAIL 22 #define MAPED_BUTTON_CHANGE_THEATRE 23 #define MAPED_BUTTON_ADVANCED_MAP_TOOLS 24 // seperator #define MAPED_BUTTON_AUDIO 26 #define MAPED_BUTTON_HELP 27 // these used to be contants which is why they are in upper case int MAPED_MAXBRUSH_W; int MAPED_MAXBRUSH_H; #define MOUSE_HINT_X (mouse_x + 20) #define MOUSE_HINT_Y (mouse_y + 20) // code void MAPED_PickPrevObject() { switch( MAPED_EditMode) { case MAPED_EM_TILES: MAPED_CurrentTile--; if( MAPED_CurrentTile < 0) { if( MISC_UsingExtendedTileset()) MAPED_CurrentTile = (MAX_TILES * 2)-1; else MAPED_CurrentTile = MAX_TILES -1; } break; case MAPED_EM_SPRITES: MAPED_CurrentSprite--; if( MAPED_CurrentSprite < 0) { MAPED_CurrentSprite = DAT_LoadedSprites.count -1; } break; case MAPED_EM_UNITS: MAPED_CurrentUnit--; if( MAPED_CurrentUnit < 0) { MAPED_CurrentUnit = DAT_LoadedRaces.count -1; } break; case MAPED_EM_POWERUPS: MAPED_CurrentPowerUp--; if( MAPED_CurrentPowerUp < 0) { MAPED_CurrentPowerUp = DAT_NumberOfPowerUps -1; } break; } } void MAPED_PickNextObject() { int t; switch( MAPED_EditMode) { case MAPED_EM_TILES: MAPED_CurrentTile++; if( MISC_UsingExtendedTileset()) t = MAX_TILES * 2; else t = MAX_TILES; if( MAPED_CurrentTile >= t) { MAPED_CurrentTile = 0; } break; case MAPED_EM_SPRITES: MAPED_CurrentSprite++; if( MAPED_CurrentSprite >= DAT_LoadedSprites.count) { MAPED_CurrentSprite = 0; } break; case MAPED_EM_UNITS: MAPED_CurrentUnit++; if( MAPED_CurrentUnit >= DAT_LoadedRaces.count) { MAPED_CurrentUnit = 0; } break; case MAPED_EM_POWERUPS: MAPED_CurrentPowerUp++; if( MAPED_CurrentPowerUp >= DAT_NumberOfPowerUps) { MAPED_CurrentPowerUp = 0; } break; } } // delete any off-map objects void MAPED_ClipObjectsToMap() { int i, x, y; int w, h; int MapWidth, MapHeight; MapWidth = MapHeader.MapX * TILE_X; MapHeight = MapHeader.MapY * TILE_Y; // check sprites for( i=0; iw, MapPowerUps[i].y + MAP_POWERUP_BITMAP( i)->h) ) { MAPED_DeletePowerUp( i); i--; } } // check message triggers for( i=0; i MapHeader.MapX) || (NewHeight > MapHeader.MapY)) NeedsFilling = 1; else NeedsFilling = 0; // clear the double buffer blit( JG_InternalBackBuffer, JG_DoubleBuffer, 0, 0, 0, 0, SCREEN_W, SCREEN_H); // draw the form blit( FormBaseBitmap, JG_DoubleBuffer, 0, 0, wx1, wy1, FormBaseBitmap->w, FormBaseBitmap->h); // *** captions *** // current size JG_BlitText( JG_DoubleBuffer, wx1+10, wy1+25, CL_BLACK, "Current map size is %d by %d (tiles)", MapHeader.MapX, MapHeader.MapY); // new size JG_BlitText( JG_DoubleBuffer, wx1+10, wy1+60, CL_BLACK, "New Size: %d by %d", NewWidth, NewHeight); // fill tile if( NeedsFilling) { draw_sprite( JG_DoubleBuffer, Tiles[ FillTile], wx1+10, wy1+80); JG_BlitText( JG_DoubleBuffer, wx1+30, wy1+80, CL_BLACK, "Fill Tile: %d (%s)", FillTile, TileData[ FillTile].desc); } // process buttons JG_DoButton( &ok); JG_DoButton( &cancel); JG_DoButton( &ChangeWidth); JG_DoButton( &ChangeHeight); if( NeedsFilling) JG_DoButton( &PickFillTileButton); // update screen JG_UpdateScreen( MP_DEFAULT); // handle input if( ok.IsDown) { done = 1; if( (NewWidth == MapHeader.MapX) && (NewHeight == MapHeader.MapY)) { JG_MessageBox( "New size is the same size as the current map!"); done = 0; } else if ( (NewWidth < MapHeader.MapX) || (NewHeight < MapHeader.MapY)) { if( !JG_ConfirmBox( NO, "Some terrain and objects may be clipped, continue?")) done = 0; } } else if( cancel.IsDown) done = 2; else if( ChangeWidth.IsDown) JG_IntegerInputBox( &NewWidth, 60, 4000, "Enter a new map width"); else if( ChangeHeight.IsDown) JG_IntegerInputBox( &NewHeight, 60, 4000, "Enter a new map height"); else if( PickFillTileButton.IsDown) TED_SelectTile( &FillTile, 0, 0); } // destroy buttons JG_DestroyButton( &ok); JG_DestroyButton( &cancel); JG_DestroyButton( &ChangeWidth); JG_DestroyButton( &ChangeHeight); JG_DestroyButton( &PickFillTileButton); destroy_bitmap( FormBaseBitmap); if( done == 2) return; // cancel // *** new size determined, proceed to resize map *** // allocate temp terrain buffers TempTerrainData = MEM_AllocateBuf( NewWidth * NewHeight); TempTerrainMul = MEM_AllocateBuf( NewWidth * NewHeight); // fill new buffers if any new dimension is larger if( (NewWidth > MapHeader.MapX) || (NewHeight > MapHeader.MapY)) { memset( TempTerrainData, FillTile%256, NewWidth * NewHeight); memset( TempTerrainMul, FillTile/256, NewWidth * NewHeight); } /* The following values must be determined depending on whether the map is wider/thinner and shorter/taller: - SrcOx, SrcOy = Cropping offsets for old terrain - DestOx, DestOy = Starting offsets for new terrain - CopyW, CopyH = Size of area (box) to copy from old terrain to new */ if( NewWidth < MapHeader.MapX) { // new map is thinner SrcOx = (MapHeader.MapX - NewWidth)/2; DestOx = 0; CopyW = NewWidth; } else { // new map is wider SrcOx = 0; DestOx = (NewWidth - MapHeader.MapX)/2; CopyW = MapHeader.MapX; } if( NewHeight < MapHeader.MapY) { // new map is shorter SrcOy = (MapHeader.MapY - NewHeight)/2; DestOy = 0; CopyH = NewHeight; } else { // new map is taller SrcOy = 0; DestOy = (NewHeight - MapHeader.MapY)/2; CopyH = MapHeader.MapY; } //MSG_Message( "SrcOx,SrcOy = %d,%d", SrcOx, SrcOy); //MSG_Message( "DestOx,DestOy = %d,%d", DestOx, DestOy); //MSG_Message( "CopyW,CopyH = %d,%d", CopyW,CopyH); // populate the new map buffer for( y=DestOy; y-1) && (i=SZ_COUNT) && (i < SZ_COUNT*2) ) { MAPED_ox = (MapHeader.StartZones[i-SZ_COUNT].x - ((TerrainWindow->w - MapHeader.StartZones[i-SZ_COUNT].w)/2)) / TILE_X; MAPED_oy = (MapHeader.StartZones[i-SZ_COUNT].y - ((TerrainWindow->h - MapHeader.StartZones[i-SZ_COUNT].h)/2)) / TILE_Y; if( MAPED_ox < 0) MAPED_ox = 0; else if( MAPED_ox + MAPED_WindowX2 - MAPED_WindowX1 > MapHeader.MapX) MAPED_ox = MapHeader.MapX - (MAPED_WindowX2 - MAPED_WindowX1); if( MAPED_oy < 0) MAPED_oy = 0; else if( MAPED_oy + MAPED_WindowY2 - MAPED_WindowY1 > MapHeader.MapY) MAPED_oy = MapHeader.MapY - (MAPED_WindowY2 - MAPED_WindowY1); } } void MAPED_AdvancedMapProperties() { TTOOLBAR tb; INSPECTOR ins; int done, button; int night, rain, storm, battle, ConveyorsOn, IgnoreRequiredItemsInDeathmatch; night = MapHeader.night; rain = MapHeader.rain; storm = MapHeader.storm; battle = MapHeader.battle; ConveyorsOn = MapHeader.ConveyorsOn; IgnoreRequiredItemsInDeathmatch = MapHeader.IgnoreRequiredItemsInDeathmatch; JG_CreateToolbar( &tb, 0, 0, 1); JG_SetToolbarTitle( &tb, "Advanced Map Properties"); JG_AddToolbarButton( &tb, "Done", BUTTON_OK, KEY_ENTER); INS_Init( &ins, "Advanced Map Properties", 2, TOOLBAR_H + 50); INS_AddString( &ins, MapHeader.title, 127, "Map Title"); INS_AddString( &ins, MapHeader.author, 127, "Author"); INS_AddString( &ins, MapHeader.email, 127, "Author Email/Web Address"); INS_AddMapFilename( &ins, MapHeader.NextLevelNames[0], 255, "Map to start on exit flag of 1"); INS_AddMapFilename( &ins, MapHeader.NextLevelNames[1], 255, "Map to start on exit flag of 2"); INS_AddMapFilename( &ins, MapHeader.NextLevelNames[2], 255, "Map to start on exit flag of 3"); INS_AddCharacterFilename( &ins, MapHeader.PlayerCharacterFilename, "Player Character File"); INS_AddInt( &ins, &MapHeader.TimeLimit, 0, 60, "Time Limit (mins)"); INS_AddBool( &ins, &night, "Night"); INS_AddBool( &ins, &rain, "Rain"); INS_AddBool( &ins, &storm, "Storm"); INS_AddBool( &ins, &battle, "Battle"); INS_AddBool( &ins, &ConveyorsOn, "Conveyors On"); INS_AddBool( &ins, &IgnoreRequiredItemsInDeathmatch, "Ignore Required Items in Head to Head"); INS_AddExtendedTilesetFilename( &ins, MapHeader.ExtendedTilesetFilename, 255, "Extended Tileset Filename"); done = 0; while( !done) { clear_to_color( JG_DoubleBuffer, CL_EDIT_BACK); button = JG_DoToolbar( &tb); INS_DoInspector( &ins); VID_UpdateScreen( MP_DEFAULT); switch( button) { case -1: break; case 0: done=1; break; } } INS_DestroyInspector( &ins); JG_DestroyToolbar( &tb); MISC_InitTiles( YES); MapHeader.night = night; MapHeader.rain = rain; MapHeader.storm = storm; MapHeader.battle = battle; MapHeader.ConveyorsOn = ConveyorsOn; MapHeader.IgnoreRequiredItemsInDeathmatch = IgnoreRequiredItemsInDeathmatch; } void MAPED_ChangeTileBrushSize() { int x, y, NewBrushW, NewBrushH, OffY, xp, yp; char done, button; TTOOLBAR t; BITMAP *TileGrid; TileGrid = MISC_NewBitmap( (MAPED_MAXBRUSH_W * (TILE_X+1))-1, (MAPED_MAXBRUSH_H * (TILE_Y+1))-1 ); clear_to_color( TileGrid, CL_EDIT_BACK); for( y=0; yw, TileGrid->h); if( JG_MouseWithin( 0, OffY, TileGrid->w, +OffY+TileGrid->h)) { NewBrushW = (mouse_x / (TILE_X+1))+1; NewBrushH = ((mouse_y-OffY) / (TILE_Y+1))+1; BlitText( JG_DoubleBuffer, SMALL, t.x+t.w+2, 4, CL_WHITE, "%d by %d", NewBrushW, NewBrushH); rect( JG_DoubleBuffer, 0, OffY, (NewBrushW*(TILE_X+1))-1, (OffY + (NewBrushH*(TILE_Y+1)))-1, CL_YELLOW); if( mouse_b &1) { MAPED_BrushW = NewBrushW; MAPED_BrushH = NewBrushH; done = 1; // JG_NT_ResetMouse(); while( mouse_b &1); } } button = JG_DoToolbar( &t); putpixel( JG_DoubleBuffer, mouse_x, mouse_y, CL_WHITE); JG_UpdateScreen( MP_DEFAULT); switch( button) { case -1: break; case 0: done=1; break; // cancel } } JG_DestroyToolbar( &t); destroy_bitmap( TileGrid); } void MAPED_ChangeMapTheatre() { int i; TGLYPH_MENU m; JG_CreateGlyphMenu( &m); for( i=0; i= MAX_MAPMESSAGETRIGGERS) { JG_MessageBox("Only %d message triggers are allowed!"); return; } MapHeader.MessageTriggers[ MapHeader.MessageTriggersUsed ].location = (y*(MapHeader.MapX*TILE_X))+x; MapHeader.MessageTriggers[ MapHeader.MessageTriggersUsed ].MessageId = StringId; MapHeader.MessageTriggersUsed++; MSG_Message( "Inserted message trigger"); } int MAPED_MessageTriggerAt( int px, int py) { int i, x ,y; for( i=0; i < MapHeader.MessageTriggersUsed; ++i) { x = MapHeader.MessageTriggers[i].location%(MapHeader.MapX*TILE_X); y = MapHeader.MessageTriggers[i].location/(MapHeader.MapX*TILE_X); if( MISC_IsWithin( x, y, x + MESSAGETRIGGER_W, y + MESSAGETRIGGER_H, px, py) ) return i; } return -1; } void MAPED_DeleteMessageTrigger( int TriggerId) { int i; for( i=TriggerId; i < MapHeader.MessageTriggersUsed-1; ++i) MapHeader.MessageTriggers[i] = MapHeader.MessageTriggers[i+1]; MapHeader.MessageTriggersUsed--; } void MAPED_EditMessageTriggers() { int done, i; char str[MAX_MESSAGESTRINGLEN], del; TTOOLBAR t; // create the first message string if none exist if( MapHeader.MessageStringsUsed < 1) { MapHeader.MessageStringsUsed = 1; strcpy( DAT_MapMessageStrings[ 0], "Message 1"); } JG_CreateToolbar( &t, 0, 0, 0); JG_SetToolbarTitle( &t, "Message Strings"); JG_AddToolbarButton( &t, "Done", BUTTON_OK, KEY_ESC); JG_AddToolbarButton( &t, "Select", BUTTON_MESSAGE, KEY_ENTER); JG_AddToolbarButton( &t, "", BUTTON_SEPERATOR, KEY_NONE); JG_AddToolbarButton( &t, "Previous String", BUTTON_PREV, KEY_LEFT); JG_AddToolbarButton( &t, "Next String", BUTTON_NEXT, KEY_RIGHT); JG_AddToolbarButton( &t, "", BUTTON_SEPERATOR, KEY_NONE); JG_AddToolbarButton( &t, "Edit String", BUTTON_QUESTION, KEY_E); JG_AddToolbarButton( &t, "Convert Text Trigger to Sound", BUTTON_SAMPLE, KEY_S); JG_AddToolbarButton( &t, "Delete String", BUTTON_DELETE, KEY_DEL); JG_AddToolbarButton( &t, "", BUTTON_SEPERATOR, KEY_NONE); JG_AddToolbarButton( &t, "New String", BUTTON_NEW, KEY_N); done = 0; while( !done) { clear_to_color( JG_DoubleBuffer, CL_EDIT_BACK); if( MAPED_CurrentMessageString < 0) MAPED_CurrentMessageString = MapHeader.MessageStringsUsed -1; else if( MAPED_CurrentMessageString >= MapHeader.MessageStringsUsed) MAPED_CurrentMessageString = 0; BlitText( JG_DoubleBuffer, SMALL, 5, SCREEN_H - FONT_H - 2, CL_GREEN, "Message string %d of %d (%d max)", MAPED_CurrentMessageString+1, MapHeader.MessageStringsUsed, MAX_MAPMESSAGESTRINGS); // centre the message string on the screen BlitText( JG_DoubleBuffer, SMALL, (SCREEN_W-text_length( font, DAT_MapMessageStrings[ MAPED_CurrentMessageString]))/2, (SCREEN_H - FONT_H) /2, CL_YELLOW, "\"%s\"", DAT_MapMessageStrings[ MAPED_CurrentMessageString]); switch( JG_DoToolbar( &t)) { case -1: break; case 0: done=1; break; // done case 1: MAPED_EditMode = MAPED_EM_MESSAGETRIG; done = 1; break; // select // sep case 3: MAPED_CurrentMessageString--; break; // prev case 4: MAPED_CurrentMessageString++; break; // next // sep case 6: // edit string JG_StringInputBox( DAT_MapMessageStrings[ MAPED_CurrentMessageString], MAX_MESSAGESTRINGLEN-1, "Edit Message String"); break; // convert to sound trigger case 7: if( AUD_SelectSoundName( str)) { if( strlen( str) >= MAX_MESSAGESTRINGLEN) JG_MessageBox("Total string length is too long for message string"); else sprintf( DAT_MapMessageStrings[ MAPED_CurrentMessageString], "/s:%s" , str); } break; case 8: // delete if( MapHeader.MessageStringsUsed < 2) { JG_MessageBox("Can not delete! At least one string must exist!"); } else { del = 1; for( i=0; i MAPED_CurrentMessageString) MapHeader.MessageTriggers[i].MessageId--; } else JG_MessageBox("No strings were deleted"); } break; // sep case 10: // add new string if( MapHeader.MessageStringsUsed >= MAX_MAPMESSAGESTRINGS) { JG_MessageBox("Only %d message strings are allowed!", MAX_MAPMESSAGESTRINGS); } else { DAT_MapMessageStrings[ MapHeader.MessageStringsUsed][0] = 0; if( JG_StringInputBox( DAT_MapMessageStrings[ MapHeader.MessageStringsUsed], MAX_MESSAGESTRINGLEN-1, "New Message String")) { MapHeader.MessageStringsUsed++; MAPED_CurrentMessageString = MapHeader.MessageStringsUsed-1; } else JG_MessageBox("No strings were added"); } break; } VID_UpdateScreen( MP_DEFAULT); } JG_DestroyToolbar( &t); } void MAPED_UnitRightClickMenu( int unit) { TGLYPH_MENU menu; BITMAP *back; JG_CreateGlyphMenu( &menu); JG_AddGlyphMenuItem( &menu, "Toggle Unit Active", BUTTON_UNIT); JG_AddGlyphMenuItem( &menu, "Delete Unit", BUTTON_DELETE); JG_AddGlyphMenuItem( &menu, "Cancel", BUTTON_CANCEL); back = MISC_NewBitmap( SCREEN_W, SCREEN_H); blit( JG_DoubleBuffer, back, 0, 0, 0, 0, SCREEN_W, SCREEN_H); switch( JG_GlyphMenu( &menu, mouse_x, mouse_y, back) ) { case 0: MapUnits[unit].StartActive = !MapUnits[unit].StartActive; break; // toggle active case 1: MAPED_DeleteUnit(unit); break; case 2: break; // cancel } JG_DestroyGlyphMenu( &menu); destroy_bitmap( back); } void MAPED_SpriteRightClickMenu( int sprite) { TGLYPH_MENU menu; BITMAP *back; JG_CreateGlyphMenu( &menu); JG_AddGlyphMenuItem( &menu, "Set Sprite Angle", BUTTON_ROTATE); JG_AddGlyphMenuItem( &menu, "Delete Sprite", BUTTON_DELETE_SPRITE); JG_AddGlyphMenuItem( &menu, "Cancel", BUTTON_CANCEL); back = MISC_NewBitmap( SCREEN_W, SCREEN_H); blit( JG_DoubleBuffer, back, 0, 0, 0, 0, SCREEN_W, SCREEN_H); switch( JG_GlyphMenu( &menu, mouse_x, mouse_y, back) ) { case 0: MapSprites[ sprite].angle = JG_AngleSelectBox( MapSprites[ sprite].angle); break; // rotate case 1: MAPED_DeleteSprite( sprite); break; case 2: break; // cancel } JG_DestroyGlyphMenu( &menu); destroy_bitmap( back); } void MAPED_RunMap() { if( !JG_ConfirmBox( NO, "Map will be autosaved, continue?") ) return; if( !MAPED_SaveMap( 0) ) { JG_MessageBox("Save failed, can not continue!"); return; } GAME_NewGame( GT_SINGLE, 1, 1, 0); GameData.level = 0; GameData.game = GT_SINGLE;; GAME_PlayMap( MAPED_CurrentFile); DAT_DrawMessages = 0; GameData.game = GT_NONE; if( !MF_ReadMapFile( MAPED_CurrentFile) ) { JG_MessageBox( "Unable to reload map!"); return; } MISC_InitTiles( YES); } void MAPED_SelectPowerUp() { int i; i = ITEMS_SelectPowerUp(); if( i != -1) { MAPED_EditMode = MAPED_EM_POWERUPS; MAPED_CurrentPowerUp = i; } } // server only (when run in-game) void MAPED_InsertPowerUp( int x, int y, int PowerUp, int inRespawnTimer, char DroppedInGame) { if( MapHeader.PowerUpsUsed >= MAX_MAP_POWERUPS) { MSG_Message("Can not insert any more power ups!"); return; } MapPowerUps[ MapHeader.PowerUpsUsed].x = x; MapPowerUps[ MapHeader.PowerUpsUsed].y = y; strcpy(MapPowerUps[ MapHeader.PowerUpsUsed].name, POWERUP_NAME( PowerUp) ); MapPowerUps[ MapHeader.PowerUpsUsed].PowerUpNumber = PowerUp; MapPowerUps[ MapHeader.PowerUpsUsed].RespawnTimer = inRespawnTimer; MapPowerUps[ MapHeader.PowerUpsUsed].DroppedInGame = DroppedInGame; MapHeader.PowerUpsUsed++; if( (GameData.game == GT_MULTI) && (GameData.server)) { // ask clients to place NET_SendNetGamePacket( DEST_PLAYER_ALL_CLIENTS, P_ITEM_ADD_POW, PowerUp, inRespawnTimer, x, y, ""); } } int MAPED_PowerUpAt( int x, int y) { int i; for( i=0; iw, MapPowerUps[i].y + MAP_POWERUP_BITMAP( i)->h, x, y) ) return i; } // not found return -1; } void MAPED_DeletePowerUp( int PowerUp) { int i; for(i=PowerUp; i= MAX_MAP_UNITS) { MSG_Message("Can not insert any more units!"); return; } MapUnits[ MapHeader.UnitsUsed].x = x; MapUnits[ MapHeader.UnitsUsed].y = y; MapUnits[ MapHeader.UnitsUsed].RaceNumber = unit; MapUnits[ MapHeader.UnitsUsed].angle = 0; MapUnits[ MapHeader.UnitsUsed].ai = AI_NORMAL; MapUnits[ MapHeader.UnitsUsed].StartActive = 0; MSG_Message("Inserted unit %d at %d, %d", unit, x, y); MapHeader.UnitsUsed++; } void MAPED_DeleteUnit( int unit) { int i; for(i=unit; iw, DAT_LoadedSprites.sprites[ sprite].frames[0].image->h); if( MISC_IsWithin( MapUnits[i].x, MapUnits[i].y, MapUnits[i].x + w, MapUnits[i].y + h, x, y) ) return i; } return -1; } void MAPED_InsertSprite( int x, int y, unsigned char angle, int DisplayTime, int sprite) { if( MapHeader.SpritesUsed >= MAX_MAP_SPRITES) { MSG_Message("Can not insert any more sprites!"); return; } MapSprites[ MapHeader.SpritesUsed].DisplayTime = DisplayTime; MapSprites[ MapHeader.SpritesUsed].x = x; MapSprites[ MapHeader.SpritesUsed].y = y; MapSprites[ MapHeader.SpritesUsed].SpriteNumber = sprite; strcpy( MapSprites[ MapHeader.SpritesUsed].SpriteName, DAT_LoadedSprites.names[ sprite] ); MapSprites[ MapHeader.SpritesUsed].angle = angle; MapSprites[ MapHeader.SpritesUsed].ConveyorCheck = 1; // reset animation data SPR_ResetAnimationData( &MapSprites[ MapHeader.SpritesUsed].AnimationData); // * if this sprite has a non looped animation and is off-screen then end the animation * // if a game is running if( GameData.game != GT_NONE) { if( DAT_LoadedSprites.sprites[ sprite].NumFrames > 1) { // if the last frame has a display time of -1 if( DAT_LoadedSprites.sprites[ sprite].frames[ DAT_LoadedSprites.sprites[ sprite].NumFrames-1 ].DisplayTime == -1) { // if the sprite is not in the GAME window if( !MISC_ObjectWithin( GameData.MapWindowX, GameData.MapWindowY, GameData.MapWindowX + ((GameData.wx2 - GameData.wx1) * TILE_X), GameData.MapWindowY + ((GameData.wy2 - GameData.wy1) * TILE_Y), ROT_MAP_SPR_X( MapHeader.SpritesUsed), ROT_MAP_SPR_Y( MapHeader.SpritesUsed), ROT_MAP_SPR_X( MapHeader.SpritesUsed) + ROT_MAP_SPR_W( MapHeader.SpritesUsed), ROT_MAP_SPR_Y( MapHeader.SpritesUsed) + ROT_MAP_SPR_H( MapHeader.SpritesUsed) )) { // end the animation (move to last frame) MapSprites[ MapHeader.SpritesUsed].AnimationData.CurrentFrame = DAT_LoadedSprites.sprites[ sprite].NumFrames -1; //MSG_Message("Ended animation for offscreen sprite %s", DAT_LoadedSprites.sprites[sprite].name); } //else // MSG_Message("Did not end animation for onscreen sprite %s", DAT_LoadedSprites.sprites[sprite].name); } } } MapHeader.SpritesUsed++; if( (GameData.game == GT_MULTI) && (GameData.server)) { // ask clients to place sprite NET_SendNetGamePacket( DEST_PLAYER_ALL_CLIENTS, P_SPR_ADD, x, y, angle, 0, DAT_LoadedSprites.names[ sprite] ); } SORT_SortMapSprites(); } void MAPED_DeleteSprite( int sprite) { int i; for(i=sprite; iw, DAT_LoadedSprites.sprites[ sprite].frames[0].image->h); if( MISC_IsWithin( MapSprites[i].x, MapSprites[i].y, MapSprites[i].x + w, MapSprites[i].y + h, x, y) ) return i; } return -1; } int MAPED_StartZoneAt( int x, int y) { int i; for( i=0; iw, MapUnits[ s].y + MAPED_DrawSpr->h) ) { // yes, so draw it GU_DrawUnitInWindow( TerrainWindow, -1, MapUnits[s].x - (MAPED_ox * TILE_X), MapUnits[s].y - (MAPED_oy * TILE_Y), &DAT_LoadedRaces.races[ MapUnits[s].RaceNumber], 0, 0, 0, 0, 0); rect( TerrainWindow, MapUnits[s].x - (MAPED_ox * TILE_X) -1, MapUnits[s].y - (MAPED_oy * TILE_Y) -1, MapUnits[s].x - (MAPED_ox * TILE_X) + DAT_LoadedSprites.sprites[ DAT_LoadedRaces.races[ MapUnits[s].RaceNumber ].StillSpriteNumber ].frames[0].image->w, MapUnits[s].y - (MAPED_oy * TILE_Y) + DAT_LoadedSprites.sprites[ DAT_LoadedRaces.races[ MapUnits[s].RaceNumber ].StillSpriteNumber ].frames[0].image->h, CL_RED); if( MapUnits[s].StartActive) textout( TerrainWindow, font, "Active", MapUnits[s].x - (MAPED_ox * TILE_X), MapUnits[s].y - (MAPED_oy * TILE_Y), CL_WHITE); } } // draw power ups for( s=0; sw, MapPowerUps[ s].y + MAP_POWERUP_BITMAP( s)->h) ) { // draw the power up draw_sprite( TerrainWindow, MAP_POWERUP_BITMAP( s), MapPowerUps[s].x - (MAPED_ox * TILE_X), MapPowerUps[s].y - (MAPED_oy * TILE_Y) ); // draw a green box around it rect( TerrainWindow, MapPowerUps[s].x - (MAPED_ox * TILE_X) -1, MapPowerUps[s].y - (MAPED_oy * TILE_Y) -1, MapPowerUps[s].x - (MAPED_ox * TILE_X) +MAP_POWERUP_BITMAP( s)->w, MapPowerUps[s].y - (MAPED_oy * TILE_Y) +MAP_POWERUP_BITMAP( s)->h, CL_GREEN); } } } } // draw message triggers for( s=0; sw, Tiles[tile]->h); blend_trans( dest, Tiles[tile], x, y, 128); } void MAPED_NewMap( int AutoCreate) { int fill, i, x, y; long l; if( AutoCreate) { // auto create a default map x = 100; y = 60; fill = 0; } else { // input map dimensions and confirmation if( !JG_ConfirmBox( NO, "Really start a new map?") ) { JG_MessageBox( "New map aborted!"); return; } if( !JG_IntegerInputBox( &x, 100, 5000, "Enter map width (in tiles)") ) return; if( !JG_IntegerInputBox( &y, 60, 5000, "Enter map height (in tiles)") ) return; if( !JG_ConfirmBox( 1, "Use default fill tile?")) { if( !TED_SelectTile( &fill, 0, 0)) return; } else fill = 0; } memset( MapHeader.author, 0, sizeof(MapHeader.author) ); memset( MapHeader.email, 0, sizeof(MapHeader.email) ); strcpy( MapHeader.author, "?"); strcpy( MapHeader.email, "?"); memset( MapHeader.title, 0, sizeof( MapHeader.title) ); strcpy( MapHeader.title, "New Map"); MapHeader.MapX = x; MapHeader.MapY = y; MapHeader.SpritesUsed = 0; MapHeader.UnitsUsed = 0; MapHeader.PowerUpsUsed = 0; MapHeader.MessageStringsUsed = 0; MapHeader.MessageTriggersUsed = 0; // * set start zone coords * MapHeader.StartZones[ SZ_SINGLE].x = DEF_SINGLE_ZONE_X; MapHeader.StartZones[ SZ_SINGLE].y = DEF_SINGLE_ZONE_Y; MapHeader.StartZones[ SZ_COOP].x = DEF_COOP_ZONE_X; MapHeader.StartZones[ SZ_COOP].y = DEF_COOP_ZONE_Y; MapHeader.StartZones[ SZ_DM2].x = DEF_DM2_ZONE_X; MapHeader.StartZones[ SZ_DM2].y = DEF_DM2_ZONE_Y; MapHeader.StartZones[ SZ_DM3].x = DEF_DM3_ZONE_X; MapHeader.StartZones[ SZ_DM3].y = DEF_DM3_ZONE_Y; MapHeader.StartZones[ SZ_DM4].x = DEF_DM4_ZONE_X; MapHeader.StartZones[ SZ_DM4].y = DEF_DM4_ZONE_Y; // * set start zone dimensions * for( i=0; i 0) { tile = MISC_GetTerrainTileFromCoords( x -1, y); if( (tile != WT_MIDDLE) && (tile != -1) ) { if( GET_TILE( x-2, y) == WT_MIDDLE) NewTile = WT_MIDDLE; else NewTile = WT_LEFT; PUT_TILE( x -1, y, NewTile); } } // check right if( x < MapHeader.MapX -1) { tile = MISC_GetTerrainTileFromCoords( x +1, y); if( (tile != WT_MIDDLE) && (tile != -1) ) { if( GET_TILE( x+2, y) == WT_MIDDLE) NewTile = WT_MIDDLE; else NewTile = WT_RIGHT; PUT_TILE( x +1, y, NewTile); } } // check top if( y > 0) { tile = MISC_GetTerrainTileFromCoords( x, y -1); if( (tile != WT_TOP_MIDDLE) && (tile != WT_MIDDLE) && (tile != -1) ) PUT_TILE( x, y -1, WT_TOP_MIDDLE); } // check bottom if( y < MapHeader.MapY -1) { tile = MISC_GetTerrainTileFromCoords( x, y +1); if( (tile != WT_BOTTOM_MIDDLE) && (tile != WT_MIDDLE) && (tile != -1) ) PUT_TILE( x, y +1, WT_BOTTOM_MIDDLE); } }*/ void MAPED_DrawStartZone( int i) { // * check and fix width and height * if( MapHeader.StartZones[i].w < MIN_START_ZONE_W) MapHeader.StartZones[i].w = MIN_START_ZONE_W; if( MapHeader.StartZones[i].h < MIN_START_ZONE_H) MapHeader.StartZones[i].h = MIN_START_ZONE_H; // bummer if the start zone is bigger than the screen - JB 13/01/2004 if( MISC_ObjectWithin( MapHeader.StartZones[i].x, MapHeader.StartZones[i].y, MapHeader.StartZones[i].x + MapHeader.StartZones[i].w, MapHeader.StartZones[i].y + MapHeader.StartZones[i].h, MAPED_ox * TILE_X, MAPED_oy * TILE_Y, (MAPED_ox + MAPED_WindowX2) * TILE_X, (MAPED_oy + MAPED_WindowX2) * TILE_Y )) { // border box rect( TerrainWindow, MapHeader.StartZones[i].x - (MAPED_ox*TILE_X), MapHeader.StartZones[i].y - (MAPED_oy*TILE_Y), MapHeader.StartZones[i].x + MapHeader.StartZones[i].w - (MAPED_ox*TILE_X), MapHeader.StartZones[i].y + MapHeader.StartZones[i].h - (MAPED_oy*TILE_Y), StartZoneColours[i]); // trans fill MISC_TransRectAbs( TerrainWindow, MapHeader.StartZones[i].x - (MAPED_ox*TILE_X) +1, MapHeader.StartZones[i].y - (MAPED_oy*TILE_Y) +1, MapHeader.StartZones[i].x + MapHeader.StartZones[i].w - (MAPED_ox*TILE_X) -1, MapHeader.StartZones[i].y + MapHeader.StartZones[i].h - (MAPED_oy*TILE_Y) -1, CL_GREY, 128); JG_BlitText( TerrainWindow, MapHeader.StartZones[i].x - (MAPED_ox*TILE_X) + ((MapHeader.StartZones[i].w - text_length( font, StartZoneNames[i]))/2), MapHeader.StartZones[i].y - (MAPED_oy*TILE_Y), CL_WHITE, StartZoneNames[i]); } } void MAPED_MapEditorLoop() { static TTIMER CursorAnimationTimer; char FileInfo[FILENAME_LEN+32]; int x, y, i, tile, colour; char StatusStr[ 256]; int TileDrawX, TileDrawY; static char ZoneResizeMode = 0; static char ZoneBeingResized; // set border colour for selected objects if( JG_IsTimerEventReady( &CursorAnimationTimer, 28)) { MAPED_BorderColour = makecol16( MAPED_BorderColourCtr, 255, 0); MAPED_BorderColourCtr+=12; } // clear double buffer clear_to_color( JG_DoubleBuffer, CL_EDIT_BACK); // * draw tile terrain * for( y=0; yw, mouse_y + MAPED_SpriteImage->h, MAPED_BorderColour); if( ((i=MAPED_SpriteAt( MAPED_SpriteInsertX, MAPED_SpriteInsertY)) != -1) && (!mouse_b&1)) { // show info on the map sprite under the mouse pointer (if any) JG_ShowHint( MOUSE_HINT_X, MOUSE_HINT_Y, "Sprite: %s - %s - Location: %d,%d - Angle: %d", DAT_LoadedSprites.sprites[ MapSprites[i].SpriteNumber].name, DAT_LoadedSprites.names[ MapSprites[i].SpriteNumber], MapSprites[i].x, MapSprites[i].y, MapSprites[i].angle ); rect( JG_DoubleBuffer, ROT_MAP_SPR_X( i) + ((MAPED_WindowX1 - MAPED_ox) * TILE_X), ROT_MAP_SPR_Y( i) + ((MAPED_WindowY1 - MAPED_oy) * TILE_Y), ROT_MAP_SPR_X( i) + ROT_MAP_SPR_W( i) + ((MAPED_WindowX1 - MAPED_ox) * TILE_X), ROT_MAP_SPR_Y( i) + ROT_MAP_SPR_H( i) + ((MAPED_WindowY1 - MAPED_oy) * TILE_Y), CL_YELLOW); } else { // show map position at mouse pointer cords JG_ShowHint( MOUSE_HINT_X, MOUSE_HINT_Y, "Map Position %d, %d", MAPED_SpriteInsertX, MAPED_SpriteInsertY); } if( mouse_b & 1) { // * insert sprite * while( mouse_b & 1); // wait for button release MAPED_InsertSprite( MAPED_SpriteInsertX, MAPED_SpriteInsertY, 0, -1, MAPED_CurrentSprite); } else if( mouse_b & 2) { // * sprite right click menu * while( mouse_b & 2); if( i != -1) MAPED_SpriteRightClickMenu( i); } break; // ******************************************************************** // * units mode * // ******************************************************************** case MAPED_EM_UNITS: // populate mode and status string strcpy( MAPED_ModeStr, "Units"); sprintf( StatusStr, "Current unit %d, %s - %d units on map", MAPED_CurrentUnit+1, DAT_LoadedRaces.races[ MAPED_CurrentUnit].desc, MapHeader.UnitsUsed); // draw current unit at mouse pointer GU_DrawUnitInWindow( JG_DoubleBuffer, -1, mouse_x, mouse_y, &DAT_LoadedRaces.races[ MAPED_CurrentUnit], 0, 0, 0, 0, 0); // show info on the map unit under the mouse pointer (if any) if( ((i=MAPED_UnitAt( MAPED_SpriteInsertX, MAPED_SpriteInsertY)) != -1) && (!mouse_b&1)) { JG_ShowHint( MOUSE_HINT_X, MOUSE_HINT_Y, "Unit: %s - %s", DAT_LoadedRaces.races[ MapUnits[i].RaceNumber].desc, DAT_LoadedRaces.names[ MapUnits[i].RaceNumber] ); } else { // show map position at mouse pointer cords JG_ShowHint( MOUSE_HINT_X, MOUSE_HINT_Y, "Map Position %d, %d", MAPED_SpriteInsertX, MAPED_SpriteInsertY); } // draw a box around the mouse pointer unit rect( JG_DoubleBuffer, mouse_x -1, mouse_y -1, mouse_x + MAPED_UnitImage->w, mouse_y + MAPED_UnitImage->h, MAPED_BorderColour); if( mouse_b & 1) { // * insert unit * while( mouse_b & 1); // wait for button release MAPED_InsertUnit( MAPED_SpriteInsertX, MAPED_SpriteInsertY, MAPED_CurrentUnit); } else if( mouse_b & 2) { //* delete unit * while( mouse_b & 2); if( i != -1) MAPED_UnitRightClickMenu(i); } break; // ******************************************************************** //* power ups mode * // ******************************************************************** case MAPED_EM_POWERUPS: // draw current power up image in the bottom left corner stretch_sprite( JG_DoubleBuffer, POWERUP_BITMAP( MAPED_CurrentPowerUp), 2, SCREEN_H - 16 -2, 16, 16); // populate mode and status strings strcpy( MAPED_ModeStr, "Power Ups"); sprintf( StatusStr, "Current power up %s - %d power ups on map", POWERUP_NAME( MAPED_CurrentPowerUp), MapHeader.PowerUpsUsed ); // draw current power up at mouse pointer draw_sprite( JG_DoubleBuffer, POWERUP_BITMAP( MAPED_CurrentPowerUp), mouse_x, mouse_y); if( mouse_b & 1) { // * insert power up * while( mouse_b & 1); MAPED_InsertPowerUp( MAPED_SpriteInsertX, MAPED_SpriteInsertY, MAPED_CurrentPowerUp, -1, 0); } else if( mouse_b & 2) { // delete power up while( mouse_b & 2); if(( i = MAPED_PowerUpAt( MAPED_SpriteInsertX, MAPED_SpriteInsertY)) != -1) MAPED_DeletePowerUp( i); } break; // ******************************************************************** // * start zones mode * // ******************************************************************** case MAPED_EM_START_ZONES: // populate mode and status strings strcpy( MAPED_ModeStr, "Start Zones"); sprintf( StatusStr, "Right click on map to move a zone, use mouse to resize"); // dragging - set zone border to mouse pos if( ZoneResizeMode != 0) { switch( ZoneResizeMode) { // right case 1: if( MAPED_SpriteInsertX > MapHeader.StartZones[ZoneBeingResized].x + MIN_START_ZONE_W) MapHeader.StartZones[ZoneBeingResized].w = MAPED_SpriteInsertX - MapHeader.StartZones[ZoneBeingResized].x; break; // bottom case 2: if( MAPED_SpriteInsertY > MapHeader.StartZones[ZoneBeingResized].y + MIN_START_ZONE_H) MapHeader.StartZones[ZoneBeingResized].h = MAPED_SpriteInsertY - MapHeader.StartZones[ZoneBeingResized].y; break; } if( !mouse_b & 1) ZoneResizeMode = 0; } if( (i = MAPED_StartZoneAt( MAPED_SpriteInsertX, MAPED_SpriteInsertY)) != -1) { // * zone under mouse * if( MAPED_SpriteInsertX == MapHeader.StartZones[i].x + MapHeader.StartZones[i].w) { MAPED_MousePointer = MP_HORIZ_RESIZE; if( (mouse_b & 1) && (ZoneResizeMode == 0) ) { // * resize right border * ZoneResizeMode = 1; // top horizontal ZoneBeingResized = i; } } else if( MAPED_SpriteInsertY == MapHeader.StartZones[i].y + MapHeader.StartZones[i].h) { MAPED_MousePointer = MP_VERT_RESIZE; if( (mouse_b & 1) && (ZoneResizeMode == 0) ) { // * resize bottom border * ZoneResizeMode = 2; // bottom horizontal ZoneBeingResized = i; } } //else // MAPED_MousePointer = MP_MOVE; // show information about the start zone under the current mouse pointer coords // NOTE Y OFFSET FOR HINT JG_ShowHint( MOUSE_HINT_X, MOUSE_HINT_Y + 30, "%s - Position %d,%d - Size %d by %d - Right click to move", StartZoneNames[i], MapHeader.StartZones[i].x, MapHeader.StartZones[i].y, MapHeader.StartZones[i].w, MapHeader.StartZones[i].h); } else { // * no zone under mouse * // show map position at mouse pointer cords JG_ShowHint( MOUSE_HINT_X, MOUSE_HINT_Y, "Map Position %d, %d", MAPED_SpriteInsertX, MAPED_SpriteInsertY); } // * draw mouse pointer image NOTE RESIZERS ARE SET IN MAPED_MousePointer and are drawn automatically * if( MAPED_MousePointer == MP_NONE) { if( i == -1) { // if not over a zone then draw the lining up lines (handy for moving zones to the mouse coords) line( JG_DoubleBuffer, mouse_x, mouse_y, mouse_x + 30, mouse_y, MAPED_BorderColour); line( JG_DoubleBuffer, mouse_x, mouse_y, mouse_x, mouse_y + 30, MAPED_BorderColour); JG_BlitText( JG_DoubleBuffer, mouse_x + JG_ICON_W + 2, mouse_y + 2, MAPED_BorderColour, "Right click for menu"); } draw_sprite( JG_DoubleBuffer, MAPED_PlayerStartBitmap, mouse_x, mouse_y); } if( mouse_b & 2) { // * move start zone menu * while( mouse_b & 2); MAPED_MovePlayerStartZonesMenu( MAPED_SpriteInsertX, MAPED_SpriteInsertY); } break; // ******************************************************************** // * message triggers mode * // ******************************************************************** case MAPED_EM_MESSAGETRIG: // populate mode and status strings strcpy( MAPED_ModeStr, "Message Triggers"); sprintf( StatusStr, "Message Trigger: \"%s\"", DAT_MapMessageStrings[ MAPED_CurrentMessageString] ); // draw a message trigger box at the mouse pointer rect( JG_DoubleBuffer, mouse_x, mouse_y, mouse_x + MESSAGETRIGGER_W, mouse_y + MESSAGETRIGGER_H, CL_YELLOW); // show map position at mouse pointer cords JG_ShowHint( MOUSE_HINT_X, MOUSE_HINT_Y, "Map Position %d, %d", MAPED_SpriteInsertX, MAPED_SpriteInsertY); if( mouse_b & 1) { // * insert message trigger * while( mouse_b & 1); // wait for button release MAPED_InsertMessageTrigger( MAPED_SpriteInsertX, MAPED_SpriteInsertY, MAPED_CurrentMessageString); } else if( mouse_b & 2) { // * delete message trigger * while( mouse_b & 2); if(( i = MAPED_MessageTriggerAt( MAPED_SpriteInsertX, MAPED_SpriteInsertY)) != -1) { MAPED_DeleteMessageTrigger( i); MSG_Message( "Message trigger deleted"); } } break; } // end switch } else { // * mouse is not over game window * MAPED_MousePointer = MP_DEFAULT; strcpy( StatusStr, ""); } // end if // draw minimap if( MAPED_MiniMap) GAME_DrawMiniMap( JG_DoubleBuffer, 2, TOOLBAR_H + 2, 0, MAPED_MiniMap, MAPED_ox, MAPED_oy, (MAPED_wx2-MAPED_wx1)/TILE_X, (MAPED_wy2-MAPED_wy1)/TILE_Y); if( !JG_MouseWithin( 0, SCREEN_H-50, SCREEN_W-1, SCREEN_H-1)) { // borrow info string strcpy( FileInfo, StatusStr); sprintf( StatusStr, "Editing %s: %s", MAPED_ModeStr, FileInfo); sprintf( FileInfo, "%s by %s (%d by %d)", MapHeader.title, MapHeader.author, MapHeader.MapX, MapHeader.MapY); MISC_DrawEditorStatusBar( FileInfo, StatusStr); } } void MAPED_AdvancedToolsMenu() { TGLYPH_MENU m; JG_CreateGlyphMenu( &m); JG_AddGlyphMenuItem( &m, "Advanced Map Properties", BUTTON_MAP); JG_AddGlyphMenuItem( &m, "Change Terrain Theatre", BUTTON_THEATRE); JG_AddGlyphMenuItem( &m, "Flip Map", BUTTON_FLIP); JG_AddGlyphMenuItem( &m, "Mirror Map", BUTTON_MIRROR); JG_AddGlyphMenuItem( &m, "Resize Map", BUTTON_REPOSITION); JG_AddGlyphMenuItem( &m, "Cancel", BUTTON_CANCEL); switch( JG_GlyphMenu( &m, mouse_x, mouse_y, NULL)) { case -1: case 5: break; case 0: MAPED_AdvancedMapProperties(); break; case 1: MAPED_ChangeMapTheatre(); break; case 2: MAPED_FlipMap(); break; case 3: MAPED_MirrorMap(); break; case 4: MAPED_ResizeMap(); break; } JG_DestroyGlyphMenu( &m); } void MAPED_FlipMap() { int x, y, buf; // flip the tiles for( y=0; y 0) MAPED_WindowY1++; MAPED_WindowX2=SCREEN_W / TILE_X; MAPED_WindowY2 = SCREEN_H / TILE_Y; // create terrain window MSG_Message("MAPED_MapEditor: Creating terrain window"); TerrainWindow = create_sub_bitmap( JG_DoubleBuffer, MAPED_wx1, MAPED_wy1, MAPED_MapWindowW, MAPED_MapWindowH); // needfix: check for NULL terrain window MAPED_ShowUnits = 1; DAT_DrawMessages = 0; done = 0; while (! done) { MAPED_MapEditorLoop(); if( !MAPED_ShowUnits) JG_ShowHint( 2, SCREEN_H - FONT_H - 4, "Hiding objects"); JG_SetToolbarTitle( &toolbar, "Map Editor - %s", MAPED_CurrentFile); // handle toolbar button = JG_DoToolbar( &toolbar); // * handle additional keyboard input * if( keypressed() ) { ch = readkey(); switch( ch >> 8) { case KEY_UP: case KEY_LEFT: button = -1; MAPED_PickPrevObject(); break; case KEY_DOWN: case KEY_RIGHT: button = -1; MAPED_PickNextObject(); break; case KEY_SPACE: button = -1; MAPED_HandyMenu(); break; default: simulate_keypress( ch); break; } } // update the screen using our desired mouse pointer VID_UpdateScreen( MAPED_MousePointer); // * deal with mouse screen scrolling * // up //MSG_Message("MAPED_MapEditor: start up scroll, done=%d", done); if( JG_MouseWithin( 0, 0, SCREEN_W, 1)) if( MAPED_oy > 0) MAPED_oy--; //MSG_Message("MAPED_MapEditor: end up scroll, done=%d", done); // down //MSG_Message("MAPED_MapEditor: start down scroll, done=%d", done); if( JG_MouseWithin( 0, SCREEN_H -2, SCREEN_W -1, SCREEN_H )) if( MAPED_oy + MAPED_WindowY2 - MAPED_WindowY1 < MapHeader.MapY) MAPED_oy++; //MSG_Message("MAPED_MapEditor: end down scroll, done=%d", done); // left //MSG_Message("MAPED_MapEditor: start left scroll, done=%d", done); if( JG_MouseWithin( 0, 0, 1, SCREEN_H -1)) if( MAPED_ox > 0) MAPED_ox--; //MSG_Message("MAPED_MapEditor: end left scroll, done=%d", done); // right //MSG_Message("MAPED_MapEditor: start right scroll, done=%d", done); if( JG_MouseWithin( SCREEN_W -2, 0, SCREEN_W -1, SCREEN_H -1)) if( MAPED_ox < MapHeader.MapX - MAPED_WindowX2 - MAPED_WindowX1) MAPED_ox++; //MSG_Message("MAPED_MapEditor: end right scroll, done=%d", done); // set the command variable to "none" //MSG_Message("MAPED_MapEditor: set cmd, done=%d", done); cmd=MAPED_NONE; //MSG_Message("MAPED_MapEditor: done setting cmd, done=%d", done); //MSG_Message("MAPED_MapEditor: switch(button), done=%d", done); switch( button) { case -1: break; case MAPED_BUTTON_NEW: cmd=MAPED_NEW_MAP; break; case MAPED_BUTTON_LOAD: cmd=MAPED_LOAD_MAP; break; case MAPED_BUTTON_SAVE: cmd=MAPED_SAVE_MAP; break; case MAPED_BUTTON_SAVE_AS: cmd=MAPED_SAVE_MAP_AS; break; case MAPED_BUTTON_EXIT: cmd=MAPED_EXIT; break; case MAPED_BUTTON_BRUSH_SIZE: cmd=MAPED_BRUSH_SIZE; break; case MAPED_BUTTON_MINIMAP_MODE: cmd=MAPED_MINIMAP_MODE; break; case MAPED_BUTTON_RUN_MAP: cmd=MAPED_RUN_MAP; break; case MAPED_BUTTON_CHANGE_DESC: cmd=MAPED_CHANGE_DESC; break; case MAPED_BUTTON_SELECT_TILE: cmd=MAPED_SELECT_TILE; break; case MAPED_BUTTON_SELECT_SPRITE: cmd=MAPED_SELECT_SPRITE; break; case MAPED_BUTTON_SELECT_UNIT: cmd=MAPED_SELECT_UNIT; break; case MAPED_BUTTON_SELECT_POWER: cmd=MAPED_SELECT_POWER; break; case MAPED_BUTTON_AUDIO: cmd=MAPED_AUDIO; break; case MAPED_BUTTON_PLAYER_START: cmd=MAPED_PLAYER_START; break; case MAPED_BUTTON_CHANGE_THEATRE: cmd=MAPED_CHANGE_THEATRE; break; case MAPED_BUTTON_MESSAGE_TRIGGERS: cmd=MAPED_MESSAGE_TRIGGERS; break; case MAPED_BUTTON_AUTHOR: cmd=MAPED_AUTHOR; break; case MAPED_BUTTON_EMAIL: cmd=MAPED_EMAIL; break; case MAPED_BUTTON_TOGGLE_SHOW_UNITS: cmd=MAPED_TOGGLE_SHOW_UNITS; break; case MAPED_BUTTON_TOGGLE_PASSABLE_MAP: cmd = MAPED_TOGGLE_PASSABLE_MAP; break; case MAPED_BUTTON_ADVANCED_MAP_TOOLS: cmd = MAPED_ADVANCED_MAP_TOOLS; break; case MAPED_BUTTON_HELP: cmd=MAPED_HELP; break; } //MSG_Message("MAPED_MapEditor: end switch(button), done=%d", done); //MSG_Message("MAPED_MapEditor: switch(cmd), cmd = %d, done=%d", cmd, done); // do what the command variable wants switch( cmd) { case MAPED_NONE: break; case MAPED_NEW_MAP: MAPED_NewMap( 0); break; case MAPED_LOAD_MAP: MAPED_LoadMap(); break; case MAPED_SAVE_MAP: MAPED_SaveMap( NO); break; case MAPED_SAVE_MAP_AS: MAPED_SaveMap( YES); break; case MAPED_EXIT: if( JG_ConfirmBox( YES, "Exit Map Editor, any unsaved changes will be lost! Continue?") == YES) { //MSG_Message("Yes clicked on exit confirmation dialog"); done = 1; } break; case MAPED_CHANGE_DESC: MAPED_ChangeDesc(); break; case MAPED_SELECT_TILE: MAPED_SelectTile(); break; case MAPED_SELECT_SPRITE: MAPED_SelectSprite(); break; case MAPED_SELECT_UNIT: MAPED_SelectUnit(); break; case MAPED_SELECT_POWER: MAPED_SelectPowerUp(); break; case MAPED_RUN_MAP: MAPED_RunMap(); break; case MAPED_AUDIO: DLG_AudioPanel(); break; case MAPED_PLAYER_START: MAPED_EditMode = MAPED_EM_START_ZONES; break; case MAPED_MESSAGE_TRIGGERS: MAPED_EditMessageTriggers(); break; case MAPED_CHANGE_THEATRE: MAPED_ChangeMapTheatre(); break; case MAPED_MINIMAP_MODE: MAPED_MiniMap++; if( MAPED_MiniMap > 2) MAPED_MiniMap = 0; break; case MAPED_BRUSH_SIZE: MAPED_ChangeTileBrushSize(); break; case MAPED_AUTHOR: MAPED_ChangeAuthor(); break; case MAPED_EMAIL: MAPED_ChangeEmail(); break; case MAPED_TOGGLE_SHOW_UNITS: MAPED_ShowUnits = !MAPED_ShowUnits; break; case MAPED_TOGGLE_PASSABLE_MAP: ShowPassableMap = !ShowPassableMap; break; case MAPED_ADVANCED_MAP_TOOLS: MAPED_AdvancedToolsMenu(); break; case MAPED_HELP: MISC_DisplayHelpTopic( "mapedit", "Map Editor Help"); break; } //MSG_Message("MAPED_MapEditor: end switch(cmd), done=%d", done); } //MSG_Message("MAPED_MapEditor: Exiting map editor"); // clean up DAT_DrawMessages = 1; //MSG_Message("MAPED_MapEditor: Destroying toolbar"); JG_DestroyToolbar( &toolbar); //MSG_Message("MAPED_MapEditor: Done destroying toolbar"); //MSG_Message("MAPED_MapEditor: Destroying player start bitmap"); destroy_bitmap( MAPED_PlayerStartBitmap); //MSG_Message("MAPED_MapEditor: Done destroying player start bitmap"); //MSG_Message("MAPED_MapEditor: Destroying terrain window"); destroy_bitmap( TerrainWindow); //MSG_Message("MAPED_MapEditor: Done destroying terrain window"); // lose terrain //MSG_Message("MAPED_MapEditor: Destroying terrain"); TER_DestroyTerrain(); //MSG_Message("MAPED_MapEditor: Done destroying terrain"); // lose tiles //MSG_Message("MAPED_MapEditor: Destroying Tiles"); TED_DestroyTiles(); //MSG_Message("MAPED_MapEditor: Done destroying Tiles"); //MSG_Message("MAPED_MapEditor: Exited map editor, returning to menu..."); }