Simple Cusom Maplist

Post tutorials on how to do certain tasks within game or engine code here.
Post Reply
Rikku2000
Posts: 49
Joined: Wed Oct 20, 2010 6:33 pm
Location: Germany
Contact:

Simple Cusom Maplist

Post by Rikku2000 »

Here my code for a Simple Custom Maplist for Quake

First we have to define the new menu, add m_maplist after m_gameoptions
in the enum {...}

now we define the menu voids:
void M_Menu_MapList_f (void);
void M_MapList_Draw (void);
void M_MapList_Key (int key);

so at first we have defined all new menus

now an copy&past code add it after "void M_GameOptions_Key (int key)":

Code: Select all

//=============================================================================
/* MAPLIST MENU */

#include <sys/dirent.h>

#define MAX_FILE_LIST 15

int initState = 1;
int numFiles = 0;
int minFile = 0;
int maxFile = MAX_FILE_LIST;
struct dirent **nombres;
char listaFiles[MAX_FILE_LIST][256];
char nombreFile[MAX_FILE_LIST];
int arrowY = 35;
int posArrow = 0;
int numFileList = 0;
int lastArrowY = 0;

void DeleteArray (char listaFiles[MAX_FILE_LIST][256], int numFileList) {
	int i;

	for (i = 0; i < numFileList; i++)
		strcpy(listaFiles[i], "0");
}

void FileNames (char listaFiles[MAX_FILE_LIST][256], int numFileList) {
	int y = 35;
	int i;

	for(i = 0; i < numFileList; i++) {
		M_Print (74, y, listaFiles[i]);

		y += 8;
	}
}

int isFile(const struct dirent *nombre) {
	int isFile = 0;

	char *extension = strrchr(nombre->d_name, '.');

	if (strcmp(extension, ".bsp") == 0)
		isFile = 1;

	return isFile;
}

void M_Menu_MapList_f (void)
{
	key_dest = key_menu;
	m_state = m_maplist;
	m_entersound = true;

	if(initState) {
		numFiles = scandir(va("%s/maps", GAMENAME), &nombres, isFile, alphasort);

		if (numFiles < MAX_FILE_LIST) {
			maxFile = numFiles;
			numFileList = numFiles;
		} else
			numFileList = MAX_FILE_LIST;

		DeleteArray(listaFiles, numFileList);

		int x = 0;
		int i;

		for (i = minFile; i < maxFile; i++){
			strcpy(listaFiles[x], nombres[i]->d_name);
			x++;
		}

		initState = 0;
	}
}

void M_MapList_Draw (void)
{
	qpic_t	*p;
	int		x;

	M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
	p = Draw_CachePic ("gfx/p_multi.lmp");
	M_DrawPic ( (320-p->width)/2, 4, p);

	M_DrawTextBox (56, 27, 23, 15);
	if (!numFileList) {
		M_PrintWhite (104, 59, "Empty Map list");
		return;
	} else
		FileNames(listaFiles, numFileList);

	M_DrawCharacter (64, arrowY, 12 + ((int)(realtime * 4) & 1));
}

void M_MapList_Key (int key)
{
	switch (key)
	{
	case K_ESCAPE:
		M_Menu_GameOptions_f ();
		break;

	case K_UPARROW:
		S_LocalSound ("misc/menu1.wav");
		arrowY -= 8;
		posArrow--;

		if (posArrow < 0) {
			if (minFile != 0) {
				minFile--;
				maxFile--;

				DeleteArray(listaFiles, numFileList);

				int x = 0;
				int i;

				for (i = minFile; i < maxFile; i++) {
					strcpy(listaFiles[x], nombres[i]->d_name);
					x++;
				}
			}

			arrowY = 35;
			posArrow = 0;
		}
		break;

	case K_DOWNARROW:
		S_LocalSound ("misc/menu1.wav");
		lastArrowY = arrowY;
		arrowY += 8;

		if (posArrow > numFileList-2) {
			if(maxFile+1 <= numFiles) {
				minFile++;
				maxFile++;

				DeleteArray(listaFiles, numFileList);

				int x = 0;
				int i;

				for (i = minFile; i < maxFile; i++) {
					strcpy(listaFiles[x], nombres[i]->d_name);
					x++;
				}
			}

			arrowY = lastArrowY;
		} else
			posArrow++;
		break;

	case K_ENTER:
		S_LocalSound ("misc/menu2.wav");
			strcpy(nombreFile, listaFiles[posArrow]);
			COM_StripExtension (nombreFile, nombreFile);
			COM_StripExtension (nombreFile, nombreFile);
			Cbuf_AddText (va("map %s\n", nombreFile));
			break;
	}
}
now we have to add small code in "M_Init", "M_Draw", "M_Keydown".

"M_Init" add:
Cmd_AddCommand ("menu_maplist", M_Menu_MapList_f);

"M_Draw"
case m_maplist:
M_MapList_Draw ();
break;

"M_Keydown" add:
case m_maplist:
M_MapList_Key (key);
return;

now we have an working Custom maplist.
Last edited by Rikku2000 on Sat Jan 28, 2012 11:45 am, edited 3 times in total.
I am sorry for my English...
toneddu2000
Posts: 1395
Joined: Tue Feb 24, 2009 4:39 pm
Location: Italy

Re: Simple Cusom Maplist

Post by toneddu2000 »

Thank you Rikku2000 for posting this tutorial! Unfortunately I couldn't find how to make it work :(
On windows msvc didn't find dirent.h in my sys so I had to download here and redefine it like this

Code: Select all

#include "sys/dirent.h"
and comment the part where it includes <machine/ansi.h>
Anyway I tried to follow all the steps as you wrote but it gave me a lot of errors. Since I use the italian version of MSVC2008 Express I'll try to translate them! :)

Code: Select all

1>Compiling...
1>menu.c
1>.\menu.c(4418) : warning C4013: 'DO_NOT_USE_STRCPY__USE_STRLCPY_OR_MEMCPY' non definied. It will be treated like an external one which returns an int.
1>.\menu.c(4446) : error C2065: 'm_maplist': identifier not declared
1>.\menu.c(4450) : warning C4013: 'scandir' non definied. It will be treated like an external one which returns an int.
1>.\menu.c(4450) : warning C4047: 'function': 'size_t' differs from 'char [4]' in the levels of indirect reference
1>.\menu.c(4450) : warning C4024: 'va': different types from formal parameter 2 and the effective one
1>.\menu.c(4450) : error C2198: 'va': insufficient arguments for a call
1>.\menu.c(4450) : error C2065: 'alphasort': identifier not declared
1>.\menu.c(4460) : error C2143: syntax error: ';' missed before 'type'
1>.\menu.c(4461) : error C2143: syntax error: ';' missed before 'type'
1>.\menu.c(4463) : error C2065: 'i': identifier not declared
1>.\menu.c(4463) : error C2065: 'i': identifier not declared
1>.\menu.c(4463) : error C2065: 'i': identifier not declared
1>.\menu.c(4464) : error C2065: 'x': identifier not declared
1>.\menu.c(4464) : error C2065: 'i': identifier not declared
1>.\menu.c(4465) : error C2065: 'x': identifier not declared
1>.\menu.c(4474) : error C2065: 'qpic_t': identifier not declared
1>.\menu.c(4474) : error C2065: 'p': identifier not declared
1>.\menu.c(4474) : warning C4552: '*': the operator has no effect. It was expected the operator with collateral effect.
1>.\menu.c(4475) : error C2143: syntax error: ';' missed before 'type'
1>.\menu.c(4477) : warning C4013: 'M_DrawTransPic'  non definied. It will be treated like an external one which returns an int.
1>.\menu.c(4478) : error C2065: 'p': identifier not declared
1>.\menu.c(4478) : warning C4047: '=': 'int' differs from 'cachepic_t *' in the levels of indirect reference
1>.\menu.c(4479) : error C2065: 'p': identifier not declared
1>.\menu.c(4479) : error C2223: the element on the left of i '->width' must point to a struct/union
1>.\menu.c(4479) : error C2065: 'p': identifier not declared
1>.\menu.c(4479) : error C2198: 'M_DrawPic': insufficient arguments for a call
1>.\menu.c(4507) : error C2143: syntax error: ';' missed before 'type'
1>.\menu.c(4508) : error C2143: syntax error: ';' missed before 'type'
1>.\menu.c(4510) : error C2065: 'i': identifier not declared
1>.\menu.c(4510) : error C2065: 'i': identifier not declared
1>.\menu.c(4510) : error C2065: 'i': identifier not declared
1>.\menu.c(4511) : error C2065: 'x': identifier not declared
1>.\menu.c(4511) : error C2065: 'i': identifier not declared
1>.\menu.c(4512) : error C2065: 'x': identifier not declared
1>.\menu.c(4533) : error C2143: syntax error: ';' missed before 'type'
1>.\menu.c(4534) : error C2143: syntax error: ';' missed before 'type'
1>.\menu.c(4536) : error C2065: 'i': identifier not declared
1>.\menu.c(4536) : error C2065: 'i': identifier not declared
1>.\menu.c(4536) : error C2065: 'i': identifier not declared
1>.\menu.c(4537) : error C2065: 'x': identifier not declared
1>.\menu.c(4537) : error C2065: 'i': identifier not declared
1>.\menu.c(4538) : error C2065: 'x': identifier not declared
1>.\menu.c(4549) : warning C4013: 'DO_NOT_USE_STRCAT__USE_STRLCAT_OR_MEMCPY' non definied. It will be treated like an external one which returns an int.
1>.\menu.c(4550) : warning C4047: 'funzione': 'size_t' differs from 'char *' in the levels of indirect reference
1>.\menu.c(4550) : warning C4024: 'va': different types from formal parameter 2 and the effective one
1>.\menu.c(4550) : error C2198: 'va': insufficient arguments for a call
1>.\menu.c(4921) : error C2198: 'Cmd_AddCommand': insufficient arguments for a call
1>.\menu.c(5022) : error C2065: 'm_maplist': identifier not declared
1>.\menu.c(5022) : error C2051: expression case not constant
Pwhew! There were a lot! :)
This is the file I modified ( I can't post it here because its more of 60000 lines)

And this is the dirent.h

Code: Select all

/*-
 * Copyright (c) 1989, 1993
 *	The Regents of the University of California.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed by the University of
 *	California, Berkeley and its contributors.
 * 4. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 *	@(#)dirent.h	8.3 (Berkeley) 8/10/94
 * $FreeBSD: src/sys/sys/dirent.h,v 1.11 1999/12/29 04:24:39 peter Exp $
 */

#ifndef	_SYS_DIRENT_H_
#define	_SYS_DIRENT_H_

//#include <machine/ansi.h>

/*
 * The dirent structure defines the format of directory entries returned by
 * the getdirentries(2) system call.
 *
 * A directory entry has a struct dirent at the front of it, containing its
 * inode number, the length of the entry, and the length of the name
 * contained in the entry.  These are followed by the name padded to a 4
 * byte boundary with null bytes.  All names are guaranteed null terminated.
 * The maximum length of a name in a directory is MAXNAMLEN.
 */

struct dirent {
	int d_fileno;		
	int d_reclen;		
	int  d_type; 		
	int  d_namlen;		
#ifdef _POSIX_SOURCE
	char	d_name[255 + 1];	
#else
#define	MAXNAMLEN	255
	char	d_name[MAXNAMLEN + 1];	
#endif
};

/*
 * File types
 */
#define	DT_UNKNOWN	 0
#define	DT_FIFO		 1
#define	DT_CHR		 2
#define	DT_DIR		 4
#define	DT_BLK		 6
#define	DT_REG		 8
#define	DT_LNK		10
#define	DT_SOCK		12
#define	DT_WHT		14

/*
 * Convert between stat structure types and directory types.
 */
#define	IFTODT(mode)	(((mode) & 0170000) >> 12)
#define	DTTOIF(dirtype)	((dirtype) << 12)

/*
 * The _GENERIC_DIRSIZ macro gives the minimum record length which will hold
 * the directory entry.  This requires the amount of space in struct direct
 * without the d_name field, plus enough space for the name with a terminating
 * null byte (dp->d_namlen+1), rounded up to a 4 byte boundary.
 */
#define	_GENERIC_DIRSIZ(dp) \
    ((sizeof (struct dirent) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ 3))

#ifdef _KERNEL
#define	GENERIC_DIRSIZ(dp)	_GENERIC_DIRSIZ(dp)
#endif

#endif /* !_SYS_DIRENT_H_ */
Keep in mind that I'm a SuperNoooob! :)

EDIT: I couldn't find M_Keydown. Are you sure it wasn't M_KeyEvent?
Meadow Fun!! - my first commercial game, made with FTEQW game engine
Rikku2000
Posts: 49
Joined: Wed Oct 20, 2010 6:33 pm
Location: Germany
Contact:

Re: Simple Cusom Maplist

Post by Rikku2000 »

I things its kind of my compiler hehe becouse i use cygwin and edit the sys/dirent a bit hehe here my sys/dirent.h:

Code: Select all

/* Posix dirent.h for WIN32.

   Copyright 2001, 2002, 2003, 2005, 2006, 2007, 2010 Red Hat, Inc.

   This software is a copyrighted work licensed under the terms of the
   Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
   details. */

/* Including this file should not require any Windows headers.  */

#ifndef _SYS_DIRENT_H
#define _SYS_DIRENT_H

#include <sys/types.h>
#include <limits.h>

#define	direct	dirent

#define __DIRENT_VERSION	2

#pragma pack(push,4)
#define _DIRENT_HAVE_D_TYPE
struct dirent
{
  long __d_version;			/* Used internally */
  __ino64_t d_ino;
  unsigned char d_type;
  unsigned char __d_unused1[3];
  __uint32_t __d_internal1;
  char d_name[NAME_MAX + 1];
};
#pragma pack(pop)

#define __DIRENT_COOKIE 0xdede4242

#pragma pack(push,4)
typedef struct __DIR
{
  /* This is first to set alignment in non _COMPILING_NEWLIB case.  */
  unsigned long __d_cookie;
  struct dirent *__d_dirent;
  char *__d_dirname;			/* directory name with trailing '*' */
  _off_t __d_position;			/* used by telldir/seekdir */
  int __d_fd;
  unsigned __d_internal;
  void *__handle;
  void *__fh;
  unsigned __flags;
} DIR;
#pragma pack(pop)

DIR *opendir (const char *);
DIR *fdopendir (int);
struct dirent *readdir (DIR *);
int readdir_r (DIR *, struct dirent *, struct dirent **);
void rewinddir (DIR *);
int closedir (DIR *);

int dirfd (DIR *);

#ifndef _POSIX_SOURCE
#ifndef __INSIDE_CYGWIN__
off_t telldir (DIR *);
void seekdir (DIR *, off_t loc);
#endif

int scandir (const char *__dir,
	     struct dirent ***__namelist,
	     int (*select) (const struct dirent *),
	     int (*compar) (const struct dirent **, const struct dirent **));

int alphasort (const struct dirent **__a, const struct dirent **__b);
#ifdef _DIRENT_HAVE_D_TYPE
/* File types for `d_type'.  */
enum
{
  DT_UNKNOWN = 0,
# define DT_UNKNOWN     DT_UNKNOWN
  DT_FIFO = 1,
# define DT_FIFO        DT_FIFO
  DT_CHR = 2,
# define DT_CHR         DT_CHR
  DT_DIR = 4,
# define DT_DIR         DT_DIR
  DT_BLK = 6,
# define DT_BLK         DT_BLK
  DT_REG = 8,
# define DT_REG         DT_REG
  DT_LNK = 10,
# define DT_LNK         DT_LNK
  DT_SOCK = 12,
# define DT_SOCK        DT_SOCK
  DT_WHT = 14
# define DT_WHT         DT_WHT
};

/* Convert between stat structure types and directory types.  */
# define IFTODT(mode)		(((mode) & 0170000) >> 12)
# define DTTOIF(dirtype)        ((dirtype) << 12)
#endif /* _DIRENT_HAVE_D_TYPE */
#endif /* _POSIX_SOURCE */
#endif /*_SYS_DIRENT_H*/
and the dirent.h in include dir:

Code: Select all

#ifndef _DIRENT_H_
#define _DIRENT_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <sys/dirent.h>

#if !defined(MAXNAMLEN) && !defined(_POSIX_SOURCE)
#define MAXNAMLEN 1024
#endif

#ifdef __cplusplus
}
#endif
#endif /*_DIRENT_H_*/
I am sorry for my English...
qbism
Posts: 1236
Joined: Thu Nov 04, 2004 5:51 am
Contact:

Re: Simple Cusom Maplist

Post by qbism »

Thanks for this tute. It's a great idea. Got it to work with two changes:
1. changed "strcat" to "strcpy" here- strcpy(nombreFile, listaFiles[posArrow]); Otherwise would add new map name onto the old map name.
2. I use mingw to compile for Windows. Unlike Linux gcc, mingw doesn't come with implementation of scandir, so I pasted in source for it. Don't know if would help MSVC2008 issue

Code: Select all

#include<stdlib.h>
#include<sys/types.h>

//qbism - needed for Rikku2000 maplist, but not included w/ mingw
int scandir(const char *dir, struct dirent ***namelist,
            int (*select)(const struct dirent *),
            int (*compar)(const struct dirent **, const struct dirent **)) {
  DIR *d;
  struct dirent *entry;
  register int i=0;
  size_t entrysize;

  if ((d=opendir(dir)) == NULL)
     return(-1);

  *namelist=NULL;
  while ((entry=readdir(d)) != NULL)
  {
    if (select == NULL || (select != NULL && (*select)(entry)))
    {
      *namelist=(struct dirent **)realloc((void *)(*namelist),
                 (size_t)((i+1)*sizeof(struct dirent *)));
	if (*namelist == NULL) return(-1);
	entrysize=sizeof(struct dirent)-sizeof(entry->d_name)+strlen(entry->d_name)+1;
	(*namelist)[i]=(struct dirent *)malloc(entrysize);
	if ((*namelist)[i] == NULL) return(-1);
	memcpy((*namelist)[i], entry, entrysize);
	i++;
    }
  }
  if (closedir(d)) return(-1);
  if (i == 0) return(-1);
  if (compar != NULL)
    qsort((void *)(*namelist), (size_t)i, sizeof(struct dirent *), compar);

  return(i);
}

int alphasort(const struct dirent **a, const struct dirent **b) {
  return(strcmpi((*a)->d_name, (*b)->d_name));
}
Last edited by qbism on Tue Jan 24, 2012 12:12 am, edited 1 time in total.
toneddu2000
Posts: 1395
Joined: Tue Feb 24, 2009 4:39 pm
Location: Italy

Re: Simple Cusom Maplist

Post by toneddu2000 »

I compiled it under linux too but it gave same errors. Can please someone take a look at the menu.c I posted and tell me if I committed some error?
@qbism: the part of code you write: where should I put it?
Thanks
Meadow Fun!! - my first commercial game, made with FTEQW game engine
qbism
Posts: 1236
Joined: Thu Nov 04, 2004 5:51 am
Contact:

Re: Simple Cusom Maplist

Post by qbism »

Put it in menu.c, above void SetSavename () and under #include<dirent.h>
Don't do the other stuff you tried.

Some systems are #include <sys/dirent.h>
qbism
Posts: 1236
Joined: Thu Nov 04, 2004 5:51 am
Contact:

Re: Simple Cusom Maplist

Post by qbism »

edited alphasort in snippit above, return strcmpi (case insensitive) rather than strcmp
Rikku2000
Posts: 49
Joined: Wed Oct 20, 2010 6:33 pm
Location: Germany
Contact:

Re: Simple Cusom Maplist

Post by Rikku2000 »

I thing MSVC dont handle the crosscompiler. cygwin or mingw can use the same libs and aso the include fieles mingw i a bit faster then cygwin but i perfer it its easy to handle and i use it for wii, gamecube etc too
I am sorry for my English...
Post Reply