Exemple #1
0
static void CampaignIntroDraw(void *data)
{
	// This will only draw once
	const CampaignSetting *c = data;

	GraphicsBlitBkg(&gGraphicsDevice);
	const int w = gGraphicsDevice.cachedConfig.Res.x;
	const int h = gGraphicsDevice.cachedConfig.Res.y;
	const int y = h / 4;

	// Display title + author
	char *buf;
	CMALLOC(buf, strlen(c->Title) + strlen(c->Author) + 16);
	sprintf(buf, "%s by %s", c->Title, c->Author);
	FontOpts opts = FontOptsNew();
	opts.HAlign = ALIGN_CENTER;
	opts.Area = gGraphicsDevice.cachedConfig.Res;
	opts.Pad.y = y - 25;
	FontStrOpt(buf, Vec2iZero(), opts);
	CFREE(buf);

	// Display campaign description
	// allow some slack for newlines
	if (strlen(c->Description) > 0)
	{
		CMALLOC(buf, strlen(c->Description) * 2);
		// Pad about 1/6th of the screen width total (1/12th left and right)
		FontSplitLines(c->Description, buf, w * 5 / 6);
		FontStr(buf, Vec2iNew(w / 12, y));
		CFREE(buf);
	}
}
Exemple #2
0
bool ScreenMissionBriefing(const struct MissionOptions *m)
{
	const int w = gGraphicsDevice.cachedConfig.Res.x;
	const int h = gGraphicsDevice.cachedConfig.Res.y;
	const int y = h / 4;
	MissionBriefingData mData;
	memset(&mData, 0, sizeof mData);
	mData.IsOK = true;

	// Title
	CMALLOC(mData.Title, strlen(m->missionData->Title) + 32);
	sprintf(mData.Title, "Mission %d: %s",
		m->index + 1, m->missionData->Title);
	mData.TitleOpts = FontOptsNew();
	mData.TitleOpts.HAlign = ALIGN_CENTER;
	mData.TitleOpts.Area = gGraphicsDevice.cachedConfig.Res;
	mData.TitleOpts.Pad.y = y - 25;

	// Password
	if (m->index > 0)
	{
		sprintf(
			mData.Password, "Password: %s", gAutosave.LastMission.Password);
		mData.PasswordOpts = FontOptsNew();
		mData.PasswordOpts.HAlign = ALIGN_CENTER;
		mData.PasswordOpts.Area = gGraphicsDevice.cachedConfig.Res;
		mData.PasswordOpts.Pad.y = y - 15;
	}

	// Split the description, and prepare it for typewriter effect
	mData.TypewriterCount = 0;
	// allow some slack for newlines
	CMALLOC(mData.Description, strlen(m->missionData->Description) * 2 + 1);
	CCALLOC(mData.TypewriterBuf, strlen(m->missionData->Description) * 2 + 1);
	// Pad about 1/6th of the screen width total (1/12th left and right)
	FontSplitLines(m->missionData->Description, mData.Description, w * 5 / 6);
	mData.DescriptionPos = Vec2iNew(w / 12, y);

	// Objectives
	mData.ObjectiveDescPos =
		Vec2iNew(w / 6, y + FontStrH(mData.Description) + h / 10);
	mData.ObjectiveInfoPos =
		Vec2iNew(w - (w / 6), mData.ObjectiveDescPos.y + FontH());
	mData.ObjectiveHeight = h / 12;
	mData.MissionOptions = m;

	GameLoopData gData = GameLoopDataNew(
		&mData, MissionBriefingUpdate,
		&mData, MissionBriefingDraw);
	GameLoop(&gData);
	if (mData.IsOK)
	{
		SoundPlay(&gSoundDevice, StrSound("mg"));
	}

	CFREE(mData.Title);
	CFREE(mData.Description);
	CFREE(mData.TypewriterBuf);
	return mData.IsOK;
}
Exemple #3
0
void DrawBufferInit(DrawBuffer *b, Vec2i size, GraphicsDevice *g)
{
    debug(D_MAX, "Initialising draw buffer %dx%d\n", size.x, size.y);
    b->OrigSize = size;
    CMALLOC(b->tiles, size.x * sizeof *b->tiles);
    CMALLOC(b->tiles[0], size.x * size.y * sizeof *b->tiles[0]);
    for (int i = 1; i < size.x; i++)
    {
        b->tiles[i] = b->tiles[0] + i * size.y;
    }
    b->g = g;
    debug(D_MAX, "Initialised draw buffer %dx%d\n", size.x, size.y);
}
Exemple #4
0
void DrawBufferInit(DrawBuffer *b, Vec2i size, GraphicsDevice *g)
{
	debug(D_MAX, "Initialising draw buffer %dx%d\n", size.x, size.y);
	b->OrigSize = size;
	CMALLOC(b->tiles, size.x * sizeof *b->tiles);
	CMALLOC(b->tiles[0], size.x * size.y * sizeof *b->tiles[0]);
	for (int i = 1; i < size.x; i++)
	{
		b->tiles[i] = b->tiles[0] + i * size.y;
	}
	b->g = g;
	CArrayInit(&b->displaylist, sizeof(TTileItem *));
	CArrayReserve(&b->displaylist, 32);
	debug(D_MAX, "Initialised draw buffer %dx%d\n", size.x, size.y);
}
Exemple #5
0
void PicLoad(
	Pic *p, const Vec2i size, const Vec2i offset,
	const SDL_Surface *image, const SDL_Surface *s)
{
	p->size = size;
	p->offset = Vec2iZero();
	CMALLOC(p->Data, size.x * size.y * sizeof *((Pic *)0)->Data);
	// Manually copy the pixels and replace the alpha component,
	// since our gfx device format has no alpha
	int srcI = offset.y*image->w + offset.x;
	for (int i = 0; i < size.x * size.y; i++, srcI++)
	{
		const Uint32 alpha =
			((Uint32 *)image->pixels)[srcI] >> image->format->Ashift;
		// If completely transparent, replace rgb with black (0) too
		// This is because transparency blitting checks entire pixel
		if (alpha == 0)
		{
			p->Data[i] = 0;
		}
		else
		{
			const Uint32 pixel = ((Uint32 *)s->pixels)[srcI];
			const Uint32 rgbMask =
				s->format->Rmask | s->format->Gmask | s->format->Bmask;
			p->Data[i] =
				(pixel & rgbMask) | (alpha << gGraphicsDevice.Ashift);
		}
		if ((i + 1) % size.x == 0)
		{
			srcI += image->w - size.x;
		}
	}
}
static UIObject *CreateSetKeyObjs(Vec2i pos, EditorBrush *brush)
{
	UIObject *o2;
	UIObject *c = UIObjectCreate(UITYPE_CONTEXT_MENU, 0, pos, Vec2iZero());

	UIObject *o = UIObjectCreate(
		UITYPE_CUSTOM, 0,
		Vec2iZero(), Vec2iNew(TILE_WIDTH + 4, TILE_HEIGHT + 4));
	o->ChangeFunc = BrushSetBrushTypeSetKey;
	o->u.CustomDrawFunc = DrawKey;
	o->OnFocusFunc = ActivateIndexedEditorBrush;
	o->OnUnfocusFunc = DeactivateIndexedEditorBrush;
	pos = Vec2iZero();
	for (int i = -1; i < KEY_COUNT; i++)
	{
		o2 = UIObjectCopy(o);
		o2->IsDynamicData = 1;
		CMALLOC(o2->Data, sizeof(IndexedEditorBrush));
		((IndexedEditorBrush *)o2->Data)->Brush = brush;
		((IndexedEditorBrush *)o2->Data)->ItemIndex = i;
		o2->Pos = pos;
		if (i == -1)
		{
			// -1 means no key
			CSTRDUP(o2->Tooltip, "no key");
		}
		UIObjectAddChild(c, o2);
		pos.x += o->Size.x;
	}

	UIObjectDestroy(o);
	return c;
}
Exemple #7
0
void PicLoad(
	Pic *p, const Vec2i size, const Vec2i offset, const SDL_Surface *image)
{
	p->size = size;
	p->offset = Vec2iZero();
	CMALLOC(p->Data, size.x * size.y * sizeof *((Pic *)0)->Data);
	// Manually copy the pixels and replace the alpha component,
	// since our gfx device format has no alpha
	int srcI = offset.y*image->w + offset.x;
	for (int i = 0; i < size.x * size.y; i++, srcI++)
	{
		const Uint32 pixel = ((Uint32 *)image->pixels)[srcI];
		color_t c;
		SDL_GetRGBA(pixel, image->format, &c.r, &c.g, &c.b, &c.a);
		// If completely transparent, replace rgb with black (0) too
		// This is because transparency blitting checks entire pixel
		if (c.a == 0)
		{
			p->Data[i] = 0;
		}
		else
		{
			p->Data[i] = COLOR2PIXEL(c);
		}
		if ((i + 1) % size.x == 0)
		{
			srcI += image->w - size.x;
		}
	}
}
static UIObject *CreateAddKeyObjs(Vec2i pos, EditorBrush *brush)
{
	UIObject *o2;
	UIObject *c = UIObjectCreate(UITYPE_CONTEXT_MENU, 0, pos, Vec2iZero());

	UIObject *o = UIObjectCreate(
		UITYPE_CUSTOM, 0,
		Vec2iZero(), Vec2iNew(TILE_WIDTH + 4, TILE_HEIGHT + 4));
	o->ChangeFunc = BrushSetBrushTypeAddKey;
	o->u.CustomDrawFunc = DrawKey;
	o->OnFocusFunc = ActivateIndexedEditorBrush;
	o->OnUnfocusFunc = DeactivateIndexedEditorBrush;
	pos = Vec2iZero();
	int width = 4;
	for (int i = 0; i < KEY_COUNT; i++)
	{
		o2 = UIObjectCopy(o);
		o2->IsDynamicData = 1;
		CMALLOC(o2->Data, sizeof(IndexedEditorBrush));
		((IndexedEditorBrush *)o2->Data)->Brush = brush;
		((IndexedEditorBrush *)o2->Data)->u.ItemIndex = i;
		o2->Pos = pos;
		UIObjectAddChild(c, o2);
		pos.x += o->Size.x;
		if (((i + 1) % width) == 0)
		{
			pos.x = 0;
			pos.y += o->Size.y;
		}
	}

	UIObjectDestroy(o);
	return c;
}
Exemple #9
0
static PlayerList *PlayerListNew(
	GameLoopResult (*updateFunc)(GameLoopData *, LoopRunner *),
	void (*drawFunc)(void *), void *data,
	const bool hasMenu, const bool showWinners)
{
	PlayerList *pl;
	CMALLOC(pl, sizeof *pl);
	pl->pos = svec2i_zero();
	pl->size = gGraphicsDevice.cachedConfig.Res;
	pl->scroll = 0;
	pl->updateFunc = updateFunc;
	pl->drawFunc = drawFunc;
	pl->data = data;
	pl->hasMenu = hasMenu;
	pl->showWinners = showWinners;
	CArrayInit(&pl->playerUIDs, sizeof(int));
	// Collect all players, then order by score descending
	int playersAlive = 0;
	CA_FOREACH(const PlayerData, p, gPlayerDatas)
		CArrayPushBack(&pl->playerUIDs, &p->UID);
		if (p->Lives > 0)
		{
			playersAlive++;
		}
	CA_FOREACH_END()
	qsort(
		pl->playerUIDs.data,
		pl->playerUIDs.size,
		pl->playerUIDs.elemSize,
		ComparePlayerScores);
	pl->showLastMan = playersAlive == 1;
	return pl;
}
Exemple #10
0
void AddSong(struct SongDef **songList, const char *path)
{
	struct SongDef *s;
	CMALLOC(s, sizeof(struct SongDef));
	strcpy(s->path, path);
	s->next = *songList;
	*songList = s;
}
Exemple #11
0
Pic PicCopy(const Pic *src)
{
	Pic p = *src;
	const size_t size = p.size.x * p.size.y * sizeof *p.Data;
	CMALLOC(p.Data, size);
	memcpy(p.Data, src->Data, size);
	return p;
}
Exemple #12
0
menu_t *MenuCreate(const char *name, menu_type_e type)
{
	menu_t *menu;
	CMALLOC(menu, sizeof(menu_t));
	strcpy(menu->name, name);
	menu->type = type;
	menu->parentMenu = NULL;
	return menu;
}
Exemple #13
0
UDPpacket NetInputNewPacket(NetInputChannel *n, size_t len)
{
	UDPpacket packet;
	SDLNet_Write32(n->otherHost, &packet.address.host);
	SDLNet_Write16(n->otherPort, &packet.address.port);
	packet.maxlen = packet.len = len;
	CMALLOC(packet.data, len);
	return packet;
}
Exemple #14
0
void PicTrim(Pic *pic, const bool xTrim, const bool yTrim)
{
	// Scan all pixels looking for the min/max of x and y
	struct vec2i min = pic->size;
	struct vec2i max = svec2i_zero();
	for (struct vec2i pos = svec2i_zero(); pos.y < pic->size.y; pos.y++)
	{
		for (pos.x = 0; pos.x < pic->size.x; pos.x++)
		{
			const Uint32 pixel = *(pic->Data + pos.x + pos.y * pic->size.x);
			if (pixel > 0)
			{
				min.x = MIN(min.x, pos.x);
				min.y = MIN(min.y, pos.y);
				max.x = MAX(max.x, pos.x);
				max.y = MAX(max.y, pos.y);
			}
		}
	}
	// If no opaque pixels found, don't trim
	struct vec2i newSize = pic->size;
	struct vec2i offset = svec2i_zero();
	if (min.x < max.x && min.y < max.y)
	{
		if (xTrim)
		{
			newSize.x = max.x - min.x + 1;
			offset.x = min.x;
		}
		if (yTrim)
		{
			newSize.y = max.y - min.y + 1;
			offset.y = min.y;
		}
	}
	// Trim by copying pixels
	Uint32 *newData;
	CMALLOC(newData, newSize.x * newSize.y * sizeof *newData);
	for (struct vec2i pos = svec2i_zero(); pos.y < newSize.y; pos.y++)
	{
		for (pos.x = 0; pos.x < newSize.x; pos.x++)
		{
			Uint32 *target = newData + pos.x + pos.y * newSize.x;
			const int srcIdx =
				pos.x + offset.x + (pos.y + offset.y) * pic->size.x;
			*target = *(pic->Data + srcIdx);
		}
	}
	// Replace the old data
	CFREE(pic->Data);
	pic->Data = newData;
	pic->size = newSize;
	pic->offset = svec2i_zero();
	PicTryMakeTex(pic);
}
Exemple #15
0
static UIObject *CreateAddMapItemObjsImpl(
	struct vec2i pos, CreateAddMapItemObjsImplData data)
{
	UIObject *c = UIObjectCreate(UITYPE_CONTEXT_MENU, 0, pos, svec2i_zero());
	c->OnFocusFunc = CreateAddMapItemSubObjs;
	c->IsDynamicData = true;
	CMALLOC(c->Data, sizeof(CreateAddMapItemObjsImplData));
	memcpy(c->Data, &data, sizeof data);

	return c;
}
Exemple #16
0
ASPath ASPathCopy(ASPath path)
{
    if (path) {
        const size_t size = sizeof(struct __ASPath) + (path->count * path->nodeSize);
		ASPath newPath;
		CMALLOC(newPath, size);
        memcpy(newPath, path, size);
        return newPath;
    } else {
        return NULL;
    }
}
static UIObject *CreateAddCharacterObjs(
	Vec2i pos, EditorBrush *brush, CampaignOptions *co)
{
	UIObject *c = UIObjectCreate(UITYPE_CONTEXT_MENU, 0, pos, Vec2iZero());
	// Need to update UI objects dynamically as new characters can be
	// added and removed
	c->OnFocusFunc = CreateAddCharacterSubObjs;
	c->IsDynamicData = 1;
	CMALLOC(c->Data, sizeof(EditorBrushAndCampaign));
	((EditorBrushAndCampaign *)c->Data)->Brush.Brush = brush;
	((EditorBrushAndCampaign *)c->Data)->Campaign = co;

	return c;
}
static void CreateAddCharacterSubObjs(UIObject *c, void *vData)
{
	EditorBrushAndCampaign *data = vData;
	CharacterStore *store = &data->Campaign->Setting.characters;
	if (c->Children.size == store->OtherChars.size)
	{
		return;
	}
	// Recreate the child UI objects
	c->Highlighted = NULL;
	UIObject **objs = c->Children.data;
	for (int i = 0; i < (int)c->Children.size; i++, objs++)
	{
		UIObjectDestroy(*objs);
	}
	CArrayTerminate(&c->Children);
	CArrayInit(&c->Children, sizeof c);

	UIObject *o = UIObjectCreate(
		UITYPE_CUSTOM, 0,
		Vec2iZero(), Vec2iNew(TILE_WIDTH + 4, TILE_HEIGHT * 2 + 4));
	o->ChangeFunc = BrushSetBrushTypeAddCharacter;
	o->u.CustomDrawFunc = DrawCharacter;
	o->OnFocusFunc = ActivateEditorBrushAndCampaignBrush;
	o->OnUnfocusFunc = DeactivateEditorBrushAndCampaignBrush;
	Vec2i pos = Vec2iZero();
	int width = 8;
	for (int i = 0; i < (int)store->OtherChars.size; i++)
	{
		UIObject *o2 = UIObjectCopy(o);
		Character *ch = CArrayGet(&store->OtherChars, i);
		CSTRDUP(o2->Tooltip, ch->Gun->name);
		o2->IsDynamicData = 1;
		CMALLOC(o2->Data, sizeof(EditorBrushAndCampaign));
		((EditorBrushAndCampaign *)o2->Data)->Brush.Brush = data->Brush.Brush;
		((EditorBrushAndCampaign *)o2->Data)->Campaign = data->Campaign;
		((EditorBrushAndCampaign *)o2->Data)->Brush.u.ItemIndex = i;
		o2->Pos = pos;
		UIObjectAddChild(c, o2);
		pos.x += o->Size.x;
		if (((i + 1) % width) == 0)
		{
			pos.x = 0;
			pos.y += o->Size.y;
		}
	}
	UIObjectDestroy(o);
}
Exemple #19
0
void PicFromPicPaletted(GraphicsDevice *g, Pic *pic, PicPaletted *picP)
{
	pic->size = Vec2iNew(picP->w, picP->h);
	pic->offset = Vec2iZero();
	CMALLOC(pic->Data, pic->size.x * pic->size.y * sizeof *pic->Data);
	for (int i = 0; i < pic->size.x * pic->size.y; i++)
	{
		unsigned char palette = *(picP->data + i);
		pic->Data[i] = PixelFromColor(g, PaletteToColor(palette));
		// Special case: if the palette colour is 0, it's transparent
		if (palette == 0)
		{
			pic->Data[i] = 0;
		}
	}
}
static UIObject *CreateAddObjectiveObjs(
	Vec2i pos, EditorBrush *brush, CampaignOptions *co)
{
	UIObject *c = UIObjectCreate(UITYPE_CONTEXT_MENU, 0, pos, Vec2iZero());
	// Need to update UI objects dynamically as new objectives can be
	// added and removed
	c->OnFocusFunc = CreateAddObjectiveSubObjs;
	CSTRDUP(c->Tooltip,
		"Manually place objectives\nThe rest will be randomly placed");
	c->IsDynamicData = 1;
	CMALLOC(c->Data, sizeof(EditorBrushAndCampaign));
	((EditorBrushAndCampaign *)c->Data)->Brush.Brush = brush;
	((EditorBrushAndCampaign *)c->Data)->Campaign = co;

	return c;
}
Exemple #21
0
GameLoopData *ScreenVictory(CampaignOptions *c)
{
	SoundPlay(&gSoundDevice, StrSound("victory"));
	VictoryData *data;
	CMALLOC(data, sizeof *data);
	data->Campaign = c;
	const char *finalWordsSingle[] = {
		"Ha, next time I'll use my good hand",
		"Over already? I was just warming up...",
		"There's just no good opposition to be found these days!",
		"Well, maybe I'll just do my monthly reload then",
		"Woof woof",
		"I'll just bury the bones in the back yard, he-he",
		"I just wish they'd let me try bare-handed",
		"Rambo? Who's Rambo?",
		"<in Austrian accent:> I'll be back",
		"Gee, my trigger finger is sore",
		"I need more practice. I think I missed a few shots at times"
	};
	const char *finalWordsMulti[] = {
		"United we stand, divided we conquer",
		"Nothing like good teamwork, is there?",
		"Which way is the camera?",
		"We eat bullets for breakfast and have grenades as dessert",
		"We're so cool we have to wear mittens",
	};
	if (GetNumPlayers(PLAYER_ANY, false, true) == 1)
	{
		const int numWords = sizeof finalWordsSingle / sizeof(char *);
		data->FinalWords = finalWordsSingle[rand() % numWords];
	}
	else
	{
		const int numWords = sizeof finalWordsMulti / sizeof(char *);
		data->FinalWords = finalWordsMulti[rand() % numWords];
	}
	PlayerList *pl = PlayerListNew(
		PlayerListUpdate, VictoryDraw, data, true, false);
	pl->pos.y = 75;
	pl->size.y -= pl->pos.y;
	return PlayerListLoop(pl);
}
Exemple #22
0
static bool ScreenWait(
	const char *message, void (*checkFunc)(menu_t *, void *), void *data)
{
	MenuSystem ms;
	MenuSystemInit(
		&ms, &gEventHandlers, &gGraphicsDevice,
		Vec2iZero(),
		gGraphicsDevice.cachedConfig.Res);
	ms.allowAborts = true;
	ms.root = ms.current = MenuCreateNormal("", message, MENU_TYPE_NORMAL, 0);
	MenuAddExitType(&ms, MENU_TYPE_RETURN);
	ScreenWaitData *swData;
	CMALLOC(swData, sizeof *swData);
	swData->ms = &ms;
	swData->data = data;
	MenuSetPostUpdateFunc(ms.root, checkFunc, swData, true);

	MenuLoop(&ms);
	const bool ok = !ms.hasAbort;
	MenuSystemTerminate(&ms);
	return ok;
}
static UIObject *CreateAddWreckObjs(Vec2i pos, EditorBrush *brush)
{
	UIObject *o2;
	UIObject *c = UIObjectCreate(UITYPE_CONTEXT_MENU, 0, pos, Vec2iZero());

	UIObject *o = UIObjectCreate(
		UITYPE_CUSTOM, 0,
		Vec2iZero(), Vec2iNew(TILE_WIDTH + 4, TILE_HEIGHT + 4));
	o->ChangeFunc = BrushSetBrushTypeAddWreck;
	o->u.CustomDrawFunc = DrawWreck;
	o->OnFocusFunc = ActivateIndexedEditorBrush;
	o->OnUnfocusFunc = DeactivateIndexedEditorBrush;
	pos = Vec2iZero();
	const int width = 8;
	for (int i = 0; i < (int)gMapObjects.Destructibles.size; i++)
	{
		o2 = UIObjectCopy(o);
		o2->IsDynamicData = 1;
		CMALLOC(o2->Data, sizeof(IndexedEditorBrush));
		((IndexedEditorBrush *)o2->Data)->Brush = brush;
		((IndexedEditorBrush *)o2->Data)->u.ItemIndex = i;
		o2->Pos = pos;
		UIObjectAddChild(c, o2);
		pos.x += o->Size.x;
		if (((i + 1) % width) == 0)
		{
			pos.x = 0;
			pos.y += o->Size.y;
		}
		const char **name = CArrayGet(&gMapObjects.Destructibles, i);
		const MapObject *mo = StrMapObject(*name);
		CSTRDUP(o2->Tooltip, mo->Name);
	}

	UIObjectDestroy(o);
	return c;
}
Exemple #24
0
ASPath ASPathCreate(const ASPathNodeSource *source, void *context, void *startNodeKey, void *goalNodeKey)
{
    VisitedNodes visitedNodes;
    ASNeighborList neighborList;
    Node current;
    Node goalNode;
    ASPath path = NULL;
    if (!startNodeKey || !source || !source->nodeNeighbors || source->nodeSize == 0) {
        return NULL;
    }
    
    visitedNodes = VisitedNodesCreate(source, context);
    neighborList = NeighborListCreate(source);
    current = GetNode(visitedNodes, startNodeKey);
    goalNode = GetNode(visitedNodes, goalNodeKey);
 
    // mark the goal node as the goal
    SetNodeIsGoal(goalNode);
    
    // set the starting node's estimate cost to the goal and add it to the open set
    SetNodeEstimatedCost(current,  GetPathCostHeuristic(current, goalNode));
    AddNodeToOpenSet(current, 0, NodeNull);
    
    // perform the A* algorithm
    while (HasOpenNode(visitedNodes) && !NodeIsGoal((current = GetOpenNode(visitedNodes)))) {
        size_t n;
        if (source->earlyExit) {
            const int shouldExit = source->earlyExit(visitedNodes->nodeRecordsCount, GetNodeKey(current), goalNodeKey, context);

            if (shouldExit > 0) {
                SetNodeIsGoal(current);
                break;
            } else if (shouldExit < 0) {
                break;
            }
        }
        
        RemoveNodeFromOpenSet(current);
        AddNodeToClosedSet(current);
        
        neighborList->count = 0;
        source->nodeNeighbors(neighborList, GetNodeKey(current), context);

        for (n=0; n<neighborList->count; n++) {
            const float cost = GetNodeCost(current) + NeighborListGetEdgeCost(neighborList, n);
            Node neighbor = GetNode(visitedNodes, NeighborListGetNodeKey(neighborList, n));
            
            if (!NodeHasEstimatedCost(neighbor)) {
                SetNodeEstimatedCost(neighbor, GetPathCostHeuristic(neighbor, goalNode));
            }
            
            if (NodeIsInOpenSet(neighbor) && cost < GetNodeCost(neighbor)) {
                RemoveNodeFromOpenSet(neighbor);
            }
            
            if (NodeIsInClosedSet(neighbor) && cost < GetNodeCost(neighbor)) {
                RemoveNodeFromClosedSet(neighbor);
            }
            
            if (!NodeIsInOpenSet(neighbor) && !NodeIsInClosedSet(neighbor)) {
                AddNodeToOpenSet(neighbor, cost, current);
            }
        }
    }
    
    if (NodeIsNull(goalNode)) {
        SetNodeIsGoal(current);
    }
    
    if (NodeIsGoal(current)) {
        size_t count = 0;
        Node n = current;
        size_t i;
        
        while (!NodeIsNull(n)) {
            count++;
            n = GetParentNode(n);
        }
        
        CMALLOC(path, sizeof(struct __ASPath) + (count * source->nodeSize));
        path->nodeSize = source->nodeSize;
        path->count = count;
        path->cost = GetNodeCost(current);
        
        n = current;
        for (i=count; i>0; i--) {
            memcpy(path->nodeKeys + ((i - 1) * source->nodeSize), GetNodeKey(n), source->nodeSize);
            n = GetParentNode(n);
        }
    }
    
    NeighborListDestroy(neighborList);
    VisitedNodesDestroy(visitedNodes);

    return path;
}
Exemple #25
0
void WeaponMenuCreate(
	WeaponMenu *menu,
	int numPlayers, int player, const int playerUID,
	EventHandlers *handlers, GraphicsDevice *graphics)
{
	MenuSystem *ms = &menu->ms;
	WeaponMenuData *data = &menu->data;
	Vec2i pos, size;
	int w = graphics->cachedConfig.Res.x;
	int h = graphics->cachedConfig.Res.y;

	data->display.PlayerUID = playerUID;
	data->display.currentMenu = &ms->current;
	data->display.Dir = DIRECTION_DOWN;
	data->PlayerUID = playerUID;

	switch (numPlayers)
	{
	case 1:
		// Single menu, entire screen
		pos = Vec2iNew(w / 2, 0);
		size = Vec2iNew(w / 2, h);
		break;
	case 2:
		// Two menus, side by side
		pos = Vec2iNew(player * w / 2 + w / 4, 0);
		size = Vec2iNew(w / 4, h);
		break;
	case 3:
	case 4:
		// Four corners
		pos = Vec2iNew((player & 1) * w / 2 + w / 4, (player / 2) * h / 2);
		size = Vec2iNew(w / 4, h / 2);
		break;
	default:
		CASSERT(false, "not implemented");
		pos = Vec2iNew(w / 2, 0);
		size = Vec2iNew(w / 2, h);
		break;
	}
	MenuSystemInit(ms, handlers, graphics, pos, size);
	ms->align = MENU_ALIGN_LEFT;
	ms->root = ms->current = MenuCreateNormal(
		"",
		"",
		MENU_TYPE_NORMAL,
		0);
	ms->root->u.normal.maxItems = 11;
	const CArray *weapons = &gMission.Weapons;
	for (int i = 0; i < (int)weapons->size; i++)
	{
		const GunDescription **g = CArrayGet(weapons, i);
		menu_t *gunMenu;
		if ((*g)->Description != NULL)
		{
			// Gun description menu
			gunMenu = MenuCreateNormal((*g)->name, "", MENU_TYPE_NORMAL, 0);
			char *buf;
			CMALLOC(buf, strlen((*g)->Description) * 2);
			FontSplitLines((*g)->Description, buf, size.x * 5 / 6);
			MenuAddSubmenu(gunMenu, MenuCreateBack(buf));
			CFREE(buf);
			gunMenu->u.normal.isSubmenusAlt = true;
			MenuSetCustomDisplay(gunMenu, DisplayDescriptionGunIcon, *g);
		}
		else
		{
			gunMenu = MenuCreate((*g)->name, MENU_TYPE_BASIC);
		}
		MenuAddSubmenu(ms->root, gunMenu);
	}
	MenuSetPostInputFunc(ms->root, WeaponSelect, &data->display);
	// Disable menu items where the player already has the weapon
	PlayerData *pData = PlayerDataGetByUID(playerUID);
	for (int i = 0; i < pData->weaponCount; i++)
	{
		for (int j = 0; j < (int)weapons->size; j++)
		{
			const GunDescription **g = CArrayGet(weapons, j);
			if (pData->weapons[i] == *g)
			{
				MenuDisableSubmenu(ms->root, j);
			}
		}
	}
	MenuAddSubmenu(ms->root, MenuCreateSeparator(""));
	MenuAddSubmenu(
		ms->root, MenuCreateNormal("(End)", "", MENU_TYPE_NORMAL, 0));
	// Select "(End)"
	ms->root->u.normal.index = (int)ms->root->u.normal.subMenus.size - 1;

	// Disable "Done" if no weapons selected
	if (pData->weaponCount == 0)
	{
		MenuDisableSubmenu(ms->root, (int)ms->root->u.normal.subMenus.size - 1);
	}

	MenuSetCustomDisplay(ms->root, DisplayGunIcon, NULL);
	MenuSystemAddCustomDisplay(ms, MenuDisplayPlayer, &data->display);
	MenuSystemAddCustomDisplay(ms, DisplayEquippedWeapons, data);
	MenuSystemAddCustomDisplay(
		ms, MenuDisplayPlayerControls, &data->PlayerUID);
}
void SetupQuickPlayCampaign(CampaignSetting *setting)
{
	Mission *m;
	CMALLOC(m, sizeof *m);
	MissionInit(m);
	m->WallStyle = rand() % WALL_STYLE_COUNT;
	m->FloorStyle = rand() % FLOOR_STYLE_COUNT;
	m->RoomStyle = rand() % FLOOR_STYLE_COUNT;
	m->ExitStyle = rand() % GetExitCount();
	m->KeyStyle = rand() % KEYSTYLE_COUNT;
	strcpy(
		m->DoorStyle, DoorStyleStr(rand() % gPicManager.doorStyleNames.size));
	m->Size = GenerateQuickPlayMapSize(
		ConfigGetEnum(&gConfig, "QuickPlay.MapSize"));
	m->Type = MAPTYPE_CLASSIC;	// TODO: generate different map types
	switch (m->Type)
	{
	case MAPTYPE_CLASSIC:
		m->u.Classic.Walls = GenerateQuickPlayParam(
			ConfigGetEnum(&gConfig, "QuickPlay.WallCount"), 0, 5, 15, 30);
		m->u.Classic.WallLength = GenerateQuickPlayParam(
			ConfigGetEnum(&gConfig, "QuickPlay.WallLength"), 1, 3, 6, 12);
		m->u.Classic.CorridorWidth = rand() % 3 + 1;
		m->u.Classic.Rooms.Count = GenerateQuickPlayParam(
			ConfigGetEnum(&gConfig, "QuickPlay.RoomCount"), 0, 2, 5, 12);
		m->u.Classic.Rooms.Min = rand() % 10 + 5;
		m->u.Classic.Rooms.Max = rand() % 10 + m->u.Classic.Rooms.Min;
		m->u.Classic.Rooms.Edge = 1;
		m->u.Classic.Rooms.Overlap = 1;
		m->u.Classic.Rooms.Walls = rand() % 5;
		m->u.Classic.Rooms.WallLength = rand() % 6 + 1;
		m->u.Classic.Rooms.WallPad = rand() % 4 + 1;
		m->u.Classic.Squares = GenerateQuickPlayParam(
			ConfigGetEnum(&gConfig, "QuickPlay.SquareCount"), 0, 1, 3, 6);
		m->u.Classic.Doors.Enabled = rand() % 2;
		m->u.Classic.Doors.Min = 1;
		m->u.Classic.Doors.Max = 6;
		m->u.Classic.Pillars.Count = rand() % 5;
		m->u.Classic.Pillars.Min = rand() % 3 + 1;
		m->u.Classic.Pillars.Max = rand() % 3 + m->u.Classic.Pillars.Min;
		break;
	default:
		assert(0 && "unknown map type");
		break;
	}
	CharacterStoreTerminate(&setting->characters);
	CharacterStoreInit(&setting->characters);
	int c = GenerateQuickPlayParam(
		ConfigGetEnum(&gConfig, "QuickPlay.EnemyCount"), 3, 5, 8, 12);
	SetupQuickPlayEnemies(m, c, &setting->characters);

	c = GenerateQuickPlayParam(
		ConfigGetEnum(&gConfig, "QuickPlay.ItemCount"), 0, 2, 5, 10);
	for (int i = 0; i < c; i++)
	{
		MapObjectDensity mop;
		mop.M = IndexMapObject(rand() % MapObjectsCount(&gMapObjects));
		mop.Density = GenerateQuickPlayParam(
			ConfigGetEnum(&gConfig, "QuickPlay.ItemCount"), 0, 5, 10, 20);
		CArrayPushBack(&m->MapObjectDensities, &mop);
	}
	m->EnemyDensity = (40 + (rand() % 20)) / m->Enemies.size;
	CA_FOREACH(const GunDescription, g, gGunDescriptions.Guns)
		if (g->IsRealGun)
		{
			CArrayPushBack(&m->Weapons, &g);
		}
	CA_FOREACH_END()
	m->WallMask = RandomBGColor();
	m->FloorMask = RandomBGColor();
	m->RoomMask = RandomBGColor();
	m->AltMask = RandomBGColor();

	CFREE(setting->Title);
	CSTRDUP(setting->Title, "Quick play");
	CFREE(setting->Author);
	CSTRDUP(setting->Author, "");
	CFREE(setting->Description);
	CSTRDUP(setting->Description, "");
	CArrayPushBack(&setting->Missions, m);
	CFREE(m);
}
static void CreateAddObjectiveSubObjs(UIObject *c, void *vData)
{
	EditorBrushAndCampaign *data = vData;
	Mission *m = CampaignGetCurrentMission(data->Campaign);
	// Check if the data is still the same; if so don't recreate the
	// child UI objects
	// This is because during the course of UI operations, this element
	// could be highlighted again; if we recreate then we invalidate
	// UI pointers.
	bool needToRecreate = false;
	int childIndex = 0;
	CA_FOREACH(const Objective, obj, m->Objectives)
		int secondaryCount = 1;
		const CharacterStore *store = &data->Campaign->Setting.characters;
		switch (obj->Type)
		{
		case OBJECTIVE_KILL:
			secondaryCount = (int)store->specialIds.size;
			break;
		case OBJECTIVE_COLLECT:
			break;
		case OBJECTIVE_DESTROY:
			break;
		case OBJECTIVE_RESCUE:
			secondaryCount = (int)store->prisonerIds.size;
			break;
		default:
			continue;
		}
		for (int j = 0; j < (int)secondaryCount; j++)
		{
			if ((int)c->Children.size <= childIndex)
			{
				needToRecreate = true;
				break;
			}
			UIObject *o2 = *(UIObject **)CArrayGet(&c->Children, childIndex);
			if (((EditorBrushAndCampaign *)o2->Data)->Brush.u.ItemIndex != _ca_index ||
				((EditorBrushAndCampaign *)o2->Data)->Brush.Index2 != j)
			{
				needToRecreate = true;
				break;
			}
			childIndex++;
		}
		if (needToRecreate)
		{
			break;
		}
	CA_FOREACH_END()
	if (!needToRecreate)
	{
		return;
	}

	// Recreate the child UI objects
	c->Highlighted = NULL;
	CA_FOREACH(UIObject *, obj, c->Children)
		UIObjectDestroy(*obj);
	CA_FOREACH_END()
	CArrayTerminate(&c->Children);
	CArrayInit(&c->Children, sizeof c);

	UIObject *o = UIObjectCreate(
		UITYPE_CUSTOM, 0,
		Vec2iZero(), Vec2iNew(TILE_WIDTH + 4, TILE_HEIGHT * 2 + 4));
	o->ChangeFunc = BrushSetBrushTypeAddObjective;
	o->u.CustomDrawFunc = DrawObjective;
	o->OnFocusFunc = ActivateEditorBrushAndCampaignBrush;
	o->OnUnfocusFunc = DeactivateEditorBrushAndCampaignBrush;
	Vec2i pos = Vec2iZero();
	CA_FOREACH(const Objective, obj, m->Objectives)
		int secondaryCount = 1;
		const CharacterStore *store = &data->Campaign->Setting.characters;
		switch (obj->Type)
		{
		case OBJECTIVE_KILL:
			secondaryCount = (int)store->specialIds.size;
			o->Size.y = TILE_HEIGHT * 2 + 4;
			break;
		case OBJECTIVE_COLLECT:
			o->Size.y = TILE_HEIGHT + 4;
			break;
		case OBJECTIVE_DESTROY:
			o->Size.y = TILE_HEIGHT * 2 + 4;
			break;
		case OBJECTIVE_RESCUE:
			secondaryCount = (int)store->prisonerIds.size;
			o->Size.y = TILE_HEIGHT * 2 + 4;
			break;
		default:
			continue;
		}
		for (int j = 0; j < (int)secondaryCount; j++)
		{
			UIObject *o2 = UIObjectCopy(o);
			CSTRDUP(o2->Tooltip, ObjectiveTypeStr(obj->Type));
			o2->IsDynamicData = true;
			CMALLOC(o2->Data, sizeof(EditorBrushAndCampaign));
			((EditorBrushAndCampaign *)o2->Data)->Brush.Brush =
				data->Brush.Brush;
			((EditorBrushAndCampaign *)o2->Data)->Campaign = data->Campaign;
			((EditorBrushAndCampaign *)o2->Data)->Brush.u.ItemIndex = _ca_index;
			((EditorBrushAndCampaign *)o2->Data)->Brush.Index2 = j;
			o2->Pos = pos;
			UIObjectAddChild(c, o2);
			pos.x += o->Size.x;
		}
		pos.x = 0;
		pos.y += o->Size.y;
	CA_FOREACH_END()
	UIObjectDestroy(o);
}
Exemple #28
0
static void MenuDisplaySubmenus(const MenuSystem *ms)
{
	int x = 0, yStart = 0;
	const menu_t *menu = ms->current;

	switch (menu->type)
	{
	// TODO: refactor the three menu types (normal, options, campaign) into one
	case MENU_TYPE_NORMAL:
	case MENU_TYPE_OPTIONS:
		{
			int iStart = 0;
			int iEnd = (int)menu->u.normal.subMenus.size;
			int numMenuLines = 0;
			int maxIEnd = (int)menu->u.normal.subMenus.size;
			if (menu->u.normal.maxItems > 0)
			{
				// Calculate first/last indices
				if (menu->u.normal.scroll != 0)
				{
					iStart = menu->u.normal.scroll;
				}
				maxIEnd = iStart + menu->u.normal.maxItems;
			}
			// Count the number of menu items that can fit
			// This is to account for multi-line items
			for (iEnd = iStart;
				iEnd < maxIEnd && iEnd < (int)menu->u.normal.subMenus.size;
				iEnd++)
			{
				const menu_t *subMenu =
					CArrayGet(&menu->u.normal.subMenus, iEnd);
				const int numLines = FontStrNumLines(subMenu->name);
				if (menu->u.normal.maxItems > 0 &&
					numMenuLines + numLines > menu->u.normal.maxItems)
				{
					break;
				}
				numMenuLines += numLines;
			}

			int maxWidth = 0;
			for (int i = 0; i < (int)menu->u.normal.subMenus.size; i++)
			{
				const menu_t *subMenu = CArrayGet(&menu->u.normal.subMenus, i);
				const int width = FontStrW(subMenu->name);
				if (width > maxWidth)
				{
					maxWidth = width;
				}
			}
			// Limit max width if it is larger than the menu system size
			maxWidth = MIN(ms->size.x, maxWidth);
			const bool isCentered = menu->type == MENU_TYPE_NORMAL;
			switch (ms->align)
			{
			case MENU_ALIGN_CENTER:
				x = MS_CENTER_X(*ms, maxWidth);
				if (!isCentered)
				{
					x -= 20;
				}
				break;
			case MENU_ALIGN_LEFT:
				x = ms->pos.x;
				break;
			default:
				assert(0 && "unknown alignment");
				break;
			}

			yStart = MS_CENTER_Y(*ms, numMenuLines * FontH());
			if (menu->u.normal.maxItems > 0)
			{
				// Display scroll arrows
				if (menu->u.normal.scroll != 0)
				{
					DisplayMenuItem(
						Vec2iNew(
							MS_CENTER_X(*ms, FontW('^')),
							yStart - 2 - FontH()),
						"^",
						0, 0,
						colorBlack);
				}
				if (iEnd < (int)menu->u.normal.subMenus.size - 1)
				{
					DisplayMenuItem(
						Vec2iNew(
							MS_CENTER_X(*ms, FontW('v')),
							yStart + numMenuLines*FontH() + 2),
						"v",
						0, 0,
						colorBlack);
				}
			}
			const int xOptions = x + maxWidth + 10;

			// Display normal menu items
			Vec2i pos = Vec2iNew(x, yStart);
			for (int i = iStart; i < iEnd; i++)
			{
				const menu_t *subMenu = CArrayGet(&menu->u.normal.subMenus, i);
				char *nameBuf;
				CMALLOC(nameBuf, strlen(subMenu->name) + 3);
				if (subMenu->type == MENU_TYPE_NORMAL &&
					subMenu->u.normal.isSubmenusAlt)
				{
					sprintf(nameBuf, "%s >", subMenu->name);
				}
				else
				{
					strcpy(nameBuf, subMenu->name);
				}

				switch (menu->u.normal.align)
				{
				case MENU_ALIGN_CENTER:
					pos.x = MS_CENTER_X(*ms, FontStrW(nameBuf));
					break;
				case MENU_ALIGN_LEFT:
					// Do nothing
					break;
				default:
					assert(0 && "unknown alignment");
					break;
				}

				const int yNext = DisplayMenuItem(
					pos,
					nameBuf,
					i == menu->u.normal.index,
					subMenu->isDisabled,
					subMenu->color).y + FontH();

				// display option value
				if (subMenu->type == MENU_TYPE_SET_OPTION_TOGGLE ||
					subMenu->type == MENU_TYPE_SET_OPTION_RANGE ||
					subMenu->type == MENU_TYPE_SET_OPTION_SEED ||
					subMenu->type == MENU_TYPE_SET_OPTION_UP_DOWN_VOID_FUNC_VOID ||
					subMenu->type == MENU_TYPE_SET_OPTION_RANGE_GET_SET)
				{
					const int optionInt = MenuOptionGetIntValue(subMenu);
					const Vec2i value_pos = Vec2iNew(xOptions, pos.y);
					switch (subMenu->u.option.displayStyle)
					{
					case MENU_OPTION_DISPLAY_STYLE_INT:
						{
							char buf[32];
							sprintf(buf, "%d", optionInt);
							FontStr(buf, value_pos);
						}
						break;
					case MENU_OPTION_DISPLAY_STYLE_YES_NO:
						FontStr(optionInt ? "Yes" : "No", value_pos);
						break;
					case MENU_OPTION_DISPLAY_STYLE_ON_OFF:
						FontStr(optionInt ? "On" : "Off", value_pos);
						break;
					case MENU_OPTION_DISPLAY_STYLE_STR_FUNC:
						FontStr(subMenu->u.option.uFunc.str(), value_pos);
						break;
					case MENU_OPTION_DISPLAY_STYLE_INT_TO_STR_FUNC:
						FontStr(
							subMenu->u.option.uFunc.intToStr(optionInt),
                            value_pos);
						break;
					default:
						break;
					}
				}

				pos.y = yNext;
			}
		}
		break;
	case MENU_TYPE_KEYS:
		{
			int xKeys;
			x = MS_CENTER_X(*ms, (FontW('a') * 10)) / 2;
			xKeys = x * 3;
			yStart = (gGraphicsDevice.cachedConfig.Res.y / 2) - (FontH() * 10);

			for (int i = 0; i < (int)menu->u.normal.subMenus.size; i++)
			{
				int y = yStart + i * FontH();
				int isSelected = i == menu->u.normal.index;
				const menu_t *subMenu = CArrayGet(&menu->u.normal.subMenus, i);

				const char *name = subMenu->name;
				if (isSelected &&
					subMenu->type != MENU_TYPE_SET_OPTION_CHANGE_KEY)
				{
					FontStrMask(name, Vec2iNew(x, y), colorRed);
				}
				else
				{
					FontStr(name, Vec2iNew(x, y));
				}

				if (subMenu->type == MENU_TYPE_SET_OPTION_CHANGE_KEY)
				{
					const char *keyName;
					if (menu->u.normal.changeKeyMenu == subMenu)
					{
						keyName = "Press a key";
					}
					else if (subMenu->u.changeKey.code == KEY_CODE_MAP)
					{
						keyName = SDL_GetKeyName(gConfig.Input.PlayerKeys[0].Keys.map);
					}
					else
					{
						keyName = SDL_GetKeyName(InputGetKey(
							subMenu->u.changeKey.keys,
							subMenu->u.changeKey.code));
					}
					DisplayMenuItem(
						Vec2iNew(xKeys, y),
						keyName,
						isSelected,
						0,
						colorBlack);
				}
			}
		}
		break;
	default:
		// No submenus, don't display anything
		break;
	}
}